#include "program/program.h"
#include "util/mesa-sha1.h"
#include "util/set.h"
-#include "util/string_to_uint_map.h"
+#include "string_to_uint_map.h"
#include "linker.h"
#include "link_varyings.h"
#include "ir_optimization.h"
virtual ir_visitor_status visit_leave(ir_dereference_record *ir)
{
- for (unsigned i = 0; i < ir->record->type->length; i++) {
- const struct glsl_struct_field *field =
- &ir->record->type->fields.structure[i];
- if (strcmp(field->name, ir->field) == 0) {
- ir->type = field->type;
- break;
- }
- }
+ ir->type = ir->record->type->fields.structure[ir->field_idx].type;
return visit_continue;
}
};
if (!ir->variable_referenced()->type->contains_sampler())
return visit_continue;
- if (!ir->array_index->constant_expression_value()) {
+ if (!ir->array_index->constant_expression_value(ralloc_parent(ir))) {
dynamic_sampler_array_indexing = true;
return visit_stop;
}
*
* \param shader Vertex shader executable to be verified
*/
-void
+static void
validate_vertex_shader_executable(struct gl_shader_program *prog,
struct gl_linked_shader *shader,
struct gl_context *ctx)
&shader->Program->info.cull_distance_array_size);
}
-void
+static void
validate_tess_eval_shader_executable(struct gl_shader_program *prog,
struct gl_linked_shader *shader,
struct gl_context *ctx)
*
* \param shader Fragment shader executable to be verified
*/
-void
+static void
validate_fragment_shader_executable(struct gl_shader_program *prog,
struct gl_linked_shader *shader)
{
*
* \param shader Geometry shader executable to be verified
*/
-void
+static void
validate_geometry_shader_executable(struct gl_shader_program *prog,
struct gl_linked_shader *shader,
struct gl_context *ctx)
/**
* Perform validation of global variables used across multiple shaders
*/
-void
+static void
cross_validate_globals(struct gl_shader_program *prog,
struct exec_list *ir, glsl_symbol_table *variables,
bool uniforms_only)
if (prog->IsES && (prog->data->Version != 310 ||
!var->get_interface_type()) &&
existing->data.precision != var->data.precision) {
- linker_error(prog, "declarations for %s `%s` have "
- "mismatching precision qualifiers\n",
- mode_string(var), var->name);
- return;
+ if ((existing->data.used && var->data.used) || prog->data->Version >= 300) {
+ linker_error(prog, "declarations for %s `%s` have "
+ "mismatching precision qualifiers\n",
+ mode_string(var), var->name);
+ return;
+ } else {
+ linker_warning(prog, "declarations for %s `%s` have "
+ "mismatching precision qualifiers\n",
+ mode_string(var), var->name);
+ }
}
} else
variables->add_variable(var);
/**
* Perform validation of uniforms used across multiple shader stages
*/
-void
+static void
cross_validate_uniforms(struct gl_shader_program *prog)
{
glsl_symbol_table variables;
* Populates a shaders symbol table with all global declarations
*/
static void
-populate_symbol_table(gl_linked_shader *sh)
+populate_symbol_table(gl_linked_shader *sh, glsl_symbol_table *symbols)
{
sh->symbols = new(sh) glsl_symbol_table;
- foreach_in_list(ir_instruction, inst, sh->ir) {
- ir_variable *var;
- ir_function *func;
-
- if ((func = inst->as_function()) != NULL) {
- sh->symbols->add_function(func);
- } else if ((var = inst->as_variable()) != NULL) {
- if (var->data.mode != ir_var_temporary)
- sh->symbols->add_variable(var);
- }
- }
+ _mesa_glsl_copy_symbols_from_table(sh->ir, symbols, sh->symbols);
}
* \param instructions Instruction stream where new variable declarations
* should be added.
*/
-void
+static void
remap_variables(ir_instruction *inst, struct gl_linked_shader *target,
hash_table *temps)
{
* is suitable for use as the \c last parameter of a later call to this
* function.
*/
-exec_node *
+static exec_node *
move_non_declarations(exec_list *instructions, exec_node *last,
bool make_copies, gl_linked_shader *target)
{
static void
link_xfb_stride_layout_qualifiers(struct gl_context *ctx,
struct gl_shader_program *prog,
- struct gl_linked_shader *linked_shader,
struct gl_shader **shader_list,
unsigned num_shaders)
{
*/
static void
link_bindless_layout_qualifiers(struct gl_shader_program *prog,
- struct gl_program *gl_prog,
struct gl_shader **shader_list,
unsigned num_shaders)
{
return NULL;
}
- if (!prog->data->cache_fallback)
- _mesa_reference_shader_program_data(ctx, &gl_prog->sh.data, prog->data);
+ _mesa_reference_shader_program_data(ctx, &gl_prog->sh.data, prog->data);
/* Don't use _mesa_reference_program() just take ownership */
linked->Program = gl_prog;
link_cs_input_layout_qualifiers(prog, gl_prog, shader_list, num_shaders);
if (linked->Stage != MESA_SHADER_FRAGMENT)
- link_xfb_stride_layout_qualifiers(ctx, prog, linked, shader_list,
- num_shaders);
+ link_xfb_stride_layout_qualifiers(ctx, prog, shader_list, num_shaders);
- link_bindless_layout_qualifiers(prog, gl_prog, shader_list, num_shaders);
+ link_bindless_layout_qualifiers(prog, shader_list, num_shaders);
- populate_symbol_table(linked);
+ populate_symbol_table(linked, shader_list[0]->symbols);
/* The pointer to the main function in the final linked shader (i.e., the
* copy of the original shader that contained the main function).
v.run(linked->ir);
v.fixup_unnamed_interface_types();
- if (!prog->data->cache_fallback) {
- /* Link up uniform blocks defined within this stage. */
- link_uniform_blocks(mem_ctx, ctx, prog, linked, &ubo_blocks,
- &num_ubo_blocks, &ssbo_blocks, &num_ssbo_blocks);
+ /* Link up uniform blocks defined within this stage. */
+ link_uniform_blocks(mem_ctx, ctx, prog, linked, &ubo_blocks,
+ &num_ubo_blocks, &ssbo_blocks, &num_ssbo_blocks);
- if (!prog->data->LinkStatus) {
- _mesa_delete_linked_shader(ctx, linked);
- return NULL;
- }
+ if (!prog->data->LinkStatus) {
+ _mesa_delete_linked_shader(ctx, linked);
+ return NULL;
+ }
- /* Copy ubo blocks to linked shader list */
- linked->Program->sh.UniformBlocks =
- ralloc_array(linked, gl_uniform_block *, num_ubo_blocks);
- ralloc_steal(linked, ubo_blocks);
- for (unsigned i = 0; i < num_ubo_blocks; i++) {
- linked->Program->sh.UniformBlocks[i] = &ubo_blocks[i];
- }
- linked->Program->info.num_ubos = num_ubo_blocks;
-
- /* Copy ssbo blocks to linked shader list */
- linked->Program->sh.ShaderStorageBlocks =
- ralloc_array(linked, gl_uniform_block *, num_ssbo_blocks);
- ralloc_steal(linked, ssbo_blocks);
- for (unsigned i = 0; i < num_ssbo_blocks; i++) {
- linked->Program->sh.ShaderStorageBlocks[i] = &ssbo_blocks[i];
- }
- linked->Program->info.num_ssbos = num_ssbo_blocks;
+ /* Copy ubo blocks to linked shader list */
+ linked->Program->sh.UniformBlocks =
+ ralloc_array(linked, gl_uniform_block *, num_ubo_blocks);
+ ralloc_steal(linked, ubo_blocks);
+ for (unsigned i = 0; i < num_ubo_blocks; i++) {
+ linked->Program->sh.UniformBlocks[i] = &ubo_blocks[i];
+ }
+ linked->Program->info.num_ubos = num_ubo_blocks;
+
+ /* Copy ssbo blocks to linked shader list */
+ linked->Program->sh.ShaderStorageBlocks =
+ ralloc_array(linked, gl_uniform_block *, num_ssbo_blocks);
+ ralloc_steal(linked, ssbo_blocks);
+ for (unsigned i = 0; i < num_ssbo_blocks; i++) {
+ linked->Program->sh.ShaderStorageBlocks[i] = &ssbo_blocks[i];
}
+ linked->Program->info.num_ssbos = num_ssbo_blocks;
/* At this point linked should contain all of the linked IR, so
* validate it to make sure nothing went wrong.
if (ctx->Const.VertexID_is_zero_based)
lower_vertex_id(linked);
+ if (ctx->Const.LowerCsDerivedVariables)
+ lower_cs_derived(linked);
+
#ifdef DEBUG
/* Compute the source checksum. */
linked->SourceChecksum = 0;
* \return
* Base location of the available bits on success or -1 on failure.
*/
-int
+static int
find_available_slots(unsigned used_mask, unsigned needed_count)
{
unsigned needed_mask = (1 << needed_count) - 1;
* If locations are successfully assigned, true is returned. Otherwise an
* error is emitted to the shader link log and false is returned.
*/
-bool
+static bool
assign_attribute_or_color_locations(void *mem_ctx,
gl_shader_program *prog,
struct gl_constants *constants,
} to_assign[32];
assert(max_index <= 32);
- /* Temporary array for the set of attributes that have locations assigned.
+ /* Temporary array for the set of attributes that have locations assigned,
+ * for the purpose of checking overlapping slots/components of (non-ES)
+ * fragment shader outputs.
*/
- ir_variable *assigned[16];
+ ir_variable *assigned[12 * 4]; /* (max # of FS outputs) * # components */
+ unsigned assigned_attr = 0;
unsigned num_attr = 0;
- unsigned assigned_attr = 0;
foreach_in_list(ir_instruction, node, sh->ir) {
ir_variable *const var = node->as_variable();
}
}
+ if (target_index == MESA_SHADER_FRAGMENT && !prog->IsES) {
+ /* Only track assigned variables for non-ES fragment shaders
+ * to avoid overflowing the array.
+ *
+ * At most one variable per fragment output component should
+ * reach this.
+ */
+ assert(assigned_attr < ARRAY_SIZE(assigned));
+ assigned[assigned_attr] = var;
+ assigned_attr++;
+ }
+
used_locations |= (use_mask << attr);
/* From the GL 4.5 core spec, section 11.1.1 (Vertex Attributes):
double_storage_locations |= (use_mask << attr);
}
- assigned[assigned_attr] = var;
- assigned_attr++;
-
continue;
}
GLenum programInterface, ir_variable *var,
const char *name, const glsl_type *type,
bool use_implicit_location, int location,
+ bool inouts_share_location,
const glsl_type *outermost_struct_type = NULL)
{
const glsl_type *interface_type = var->get_interface_type();
stage_mask, programInterface,
var, field_name, field->type,
use_implicit_location, field_location,
- outermost_struct_type))
+ false, outermost_struct_type))
return false;
field_location += field->type->count_attribute_slots(false);
return true;
}
+ case GLSL_TYPE_ARRAY: {
+ /* The ARB_program_interface_query spec says:
+ *
+ * "For an active variable declared as an array of basic types, a
+ * single entry will be generated, with its name string formed by
+ * concatenating the name of the array and the string "[0]"."
+ *
+ * "For an active variable declared as an array of an aggregate data
+ * type (structures or arrays), a separate entry will be generated
+ * for each active array element, unless noted immediately below.
+ * The name of each entry is formed by concatenating the name of
+ * the array, the "[" character, an integer identifying the element
+ * number, and the "]" character. These enumeration rules are
+ * applied recursively, treating each enumerated array element as a
+ * separate active variable."
+ */
+ const struct glsl_type *array_type = type->fields.array;
+ if (array_type->base_type == GLSL_TYPE_STRUCT ||
+ array_type->base_type == GLSL_TYPE_ARRAY) {
+ unsigned elem_location = location;
+ unsigned stride = inouts_share_location ? 0 :
+ array_type->count_attribute_slots(false);
+ for (unsigned i = 0; i < type->length; i++) {
+ char *elem = ralloc_asprintf(shProg, "%s[%d]", name, i);
+ if (!add_shader_variable(ctx, shProg, resource_set,
+ stage_mask, programInterface,
+ var, elem, array_type,
+ use_implicit_location, elem_location,
+ false, outermost_struct_type))
+ return false;
+ elem_location += stride;
+ }
+ return true;
+ }
+ /* fallthrough */
+ }
+
default: {
/* The ARB_program_interface_query spec says:
*
}
}
+static bool
+inout_has_same_location(const ir_variable *var, unsigned stage)
+{
+ if (!var->data.patch &&
+ ((var->data.mode == ir_var_shader_out &&
+ stage == MESA_SHADER_TESS_CTRL) ||
+ (var->data.mode == ir_var_shader_in &&
+ (stage == MESA_SHADER_TESS_CTRL || stage == MESA_SHADER_TESS_EVAL ||
+ stage == MESA_SHADER_GEOMETRY))))
+ return true;
+ else
+ return false;
+}
+
static bool
add_interface_variables(const struct gl_context *ctx,
struct gl_shader_program *shProg,
if (!add_shader_variable(ctx, shProg, resource_set,
1 << stage, programInterface,
var, var->name, var->type, vs_input_or_fs_output,
- var->data.location - loc_bias))
+ var->data.location - loc_bias,
+ inout_has_same_location(var, stage)))
return false;
}
return true;
if (!add_shader_variable(ctx, shProg, resource_set,
stage_mask,
iface, var, var->name, var->type, false,
- var->data.location - VARYING_SLOT_VAR0))
+ var->data.location - VARYING_SLOT_VAR0,
+ inout_has_same_location(var, stage)))
return false;
}
}
if (!add_shader_variable(ctx, shProg, resource_set,
1 << MESA_SHADER_FRAGMENT,
GL_PROGRAM_OUTPUT, var, var->name, var->type,
- true, var->data.location - FRAG_RESULT_DATA0))
+ true, var->data.location - FRAG_RESULT_DATA0,
+ false))
return false;
}
}
}
static int
-get_array_stride(struct gl_uniform_storage *uni, const glsl_type *interface,
- const glsl_struct_field *field, char *interface_name,
- char *var_name)
+get_array_stride(struct gl_context *ctx, struct gl_uniform_storage *uni,
+ const glsl_type *interface, const glsl_struct_field *field,
+ char *interface_name, char *var_name)
{
/* The ARB_program_interface_query spec says:
*
var_name))
return 0;
- if (interface->interface_packing != GLSL_INTERFACE_PACKING_STD430) {
+ if (GLSL_INTERFACE_PACKING_STD140 ==
+ interface->
+ get_internal_ifc_packing(ctx->Const.UseSTD430AsDefaultPacking)) {
if (array_type->is_record() || array_type->is_array())
return glsl_align(array_type->std140_size(row_major), 16);
else
}
static void
-calculate_array_size_and_stride(struct gl_shader_program *shProg,
+calculate_array_size_and_stride(struct gl_context *ctx,
+ struct gl_shader_program *shProg,
struct gl_uniform_storage *uni)
{
int block_index = uni->block_index;
if (strcmp(field->name, var_name) != 0)
continue;
- array_stride = get_array_stride(uni, interface, field,
+ array_stride = get_array_stride(ctx, uni, interface, field,
interface_name, var_name);
array_size = get_array_size(uni, field, interface_name, var_name);
goto write_top_level_array_size_and_stride;
continue;
if (is_shader_storage) {
- calculate_array_size_and_stride(shProg,
+ calculate_array_size_and_stride(ctx, shProg,
&shProg->data->UniformStorage[i]);
}
update_array_sizes(prog);
link_assign_uniform_locations(prog, ctx);
- if (!prog->data->cache_fallback) {
- link_assign_atomic_counter_resources(ctx, prog);
- link_calculate_subroutine_compat(prog);
- check_resources(ctx, prog);
- check_subroutine_resources(prog);
- check_image_resources(ctx, prog);
- link_check_atomic_counter_resources(ctx, prog);
- }
+ link_assign_atomic_counter_resources(ctx, prog);
+ link_calculate_subroutine_compat(prog);
+ check_resources(ctx, prog);
+ check_subroutine_resources(prog);
+ check_image_resources(ctx, prog);
+ link_check_atomic_counter_resources(ctx, prog);
}
static bool
if (options->LowerBufferInterfaceBlocks)
lower_ubo_reference(prog->_LinkedShaders[i],
- options->ClampBlockIndicesToArrayBounds);
+ options->ClampBlockIndicesToArrayBounds,
+ ctx->Const.UseSTD430AsDefaultPacking);
if (i == MESA_SHADER_COMPUTE)
- lower_shared_reference(prog->_LinkedShaders[i],
- &prog->Comp.SharedSize);
+ lower_shared_reference(ctx, prog, prog->_LinkedShaders[i]);
lower_vector_derefs(prog->_LinkedShaders[i]);
do_vec_index_to_swizzle(prog->_LinkedShaders[i]->ir);
last = i;
}
- if (!prog->data->cache_fallback) {
- check_explicit_uniform_locations(ctx, prog);
- link_assign_subroutine_types(prog);
- }
+ check_explicit_uniform_locations(ctx, prog);
+ link_assign_subroutine_types(prog);
if (!prog->data->LinkStatus)
goto done;
if (!prog->data->LinkStatus)
goto done;
- cross_validate_outputs_to_inputs(prog,
+ cross_validate_outputs_to_inputs(ctx, prog,
prog->_LinkedShaders[prev],
prog->_LinkedShaders[i]);
if (!prog->data->LinkStatus)
prev = i;
}
+ /* The cross validation of outputs/inputs above validates explicit locations
+ * but for SSO programs we need to do this also for the inputs in the
+ * first stage and outputs of the last stage included in the program, since
+ * there is no cross validation for these.
+ */
+ if (prog->SeparateShader)
+ validate_sso_explicit_locations(ctx, prog,
+ (gl_shader_stage) first,
+ (gl_shader_stage) last);
+
/* Cross-validate uniform blocks between shader stages */
validate_interstage_uniform_blocks(prog, prog->_LinkedShaders);
if (!prog->data->LinkStatus)
if (prog->SeparateShader)
disable_varying_optimizations_for_sso(prog);
- if (!prog->data->cache_fallback) {
- /* Process UBOs */
- if (!interstage_cross_validate_uniform_blocks(prog, false))
- goto done;
+ /* Process UBOs */
+ if (!interstage_cross_validate_uniform_blocks(prog, false))
+ goto done;
- /* Process SSBOs */
- if (!interstage_cross_validate_uniform_blocks(prog, true))
- goto done;
- }
+ /* Process SSBOs */
+ if (!interstage_cross_validate_uniform_blocks(prog, true))
+ goto done;
/* Do common optimization before assigning storage for attributes,
* uniforms, and varyings. Later optimization could possibly make