X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fnir%2Fnir_linking_helpers.c;h=28d2774cae205d7cf08c8f02b403c39a7d1423e3;hb=fd73ed1bd7e4d5a6af05d29908d6c4e2cca868b5;hp=ef0f94baf47bf5119aeac2c3314263a5f7351b81;hpb=b155f74d7bfc9daec7794074c4f644025fbddf8b;p=mesa.git diff --git a/src/compiler/nir/nir_linking_helpers.c b/src/compiler/nir/nir_linking_helpers.c index ef0f94baf47..28d2774cae2 100644 --- a/src/compiler/nir/nir_linking_helpers.c +++ b/src/compiler/nir/nir_linking_helpers.c @@ -476,7 +476,7 @@ gather_varying_component_info(nir_shader *consumer, unsigned *varying_comp_info_size, bool default_to_smooth_interp) { - unsigned store_varying_info_idx[MAX_VARYINGS_INCL_PATCH][4] = {0}; + unsigned store_varying_info_idx[MAX_VARYINGS_INCL_PATCH][4] = {{0}}; unsigned num_of_comps_to_pack = 0; /* Count the number of varying that can be packed and create a mapping @@ -726,7 +726,7 @@ nir_compact_varyings(nir_shader *producer, nir_shader *consumer, assert(producer->info.stage != MESA_SHADER_FRAGMENT); assert(consumer->info.stage != MESA_SHADER_VERTEX); - struct assigned_comps assigned_comps[MAX_VARYINGS_INCL_PATCH] = {0}; + struct assigned_comps assigned_comps[MAX_VARYINGS_INCL_PATCH] = {{0}}; get_unmoveable_components_masks(&producer->outputs, assigned_comps, producer->info.stage, @@ -970,3 +970,134 @@ nir_link_opt_varyings(nir_shader *producer, nir_shader *consumer) return progress; } + +/* TODO any better helper somewhere to sort a list? */ + +static void +insert_sorted(struct exec_list *var_list, nir_variable *new_var) +{ + nir_foreach_variable(var, var_list) { + if (var->data.location > new_var->data.location) { + exec_node_insert_node_before(&var->node, &new_var->node); + return; + } + } + exec_list_push_tail(var_list, &new_var->node); +} + +static void +sort_varyings(struct exec_list *var_list) +{ + struct exec_list new_list; + exec_list_make_empty(&new_list); + nir_foreach_variable_safe(var, var_list) { + exec_node_remove(&var->node); + insert_sorted(&new_list, var); + } + exec_list_move_nodes_to(&new_list, var_list); +} + +void +nir_assign_io_var_locations(struct exec_list *var_list, unsigned *size, + gl_shader_stage stage) +{ + unsigned location = 0; + unsigned assigned_locations[VARYING_SLOT_TESS_MAX]; + uint64_t processed_locs[2] = {0}; + + sort_varyings(var_list); + + const int base = stage == MESA_SHADER_FRAGMENT ? + (int) FRAG_RESULT_DATA0 : (int) VARYING_SLOT_VAR0; + + int UNUSED last_loc = 0; + bool last_partial = false; + nir_foreach_variable(var, var_list) { + const struct glsl_type *type = var->type; + if (nir_is_per_vertex_io(var, stage)) { + assert(glsl_type_is_array(type)); + type = glsl_get_array_element(type); + } + + unsigned var_size; + if (var->data.compact) { + /* compact variables must be arrays of scalars */ + assert(glsl_type_is_array(type)); + assert(glsl_type_is_scalar(glsl_get_array_element(type))); + unsigned start = 4 * location + var->data.location_frac; + unsigned end = start + glsl_get_length(type); + var_size = end / 4 - location; + last_partial = end % 4 != 0; + } else { + /* Compact variables bypass the normal varying compacting pass, + * which means they cannot be in the same vec4 slot as a normal + * variable. If part of the current slot is taken up by a compact + * variable, we need to go to the next one. + */ + if (last_partial) { + location++; + last_partial = false; + } + var_size = glsl_count_attribute_slots(type, false); + } + + /* Builtins don't allow component packing so we only need to worry about + * user defined varyings sharing the same location. + */ + bool processed = false; + if (var->data.location >= base) { + unsigned glsl_location = var->data.location - base; + + for (unsigned i = 0; i < var_size; i++) { + if (processed_locs[var->data.index] & + ((uint64_t)1 << (glsl_location + i))) + processed = true; + else + processed_locs[var->data.index] |= + ((uint64_t)1 << (glsl_location + i)); + } + } + + /* Because component packing allows varyings to share the same location + * we may have already have processed this location. + */ + if (processed) { + unsigned driver_location = assigned_locations[var->data.location]; + var->data.driver_location = driver_location; + + /* An array may be packed such that is crosses multiple other arrays + * or variables, we need to make sure we have allocated the elements + * consecutively if the previously proccessed var was shorter than + * the current array we are processing. + * + * NOTE: The code below assumes the var list is ordered in ascending + * location order. + */ + assert(last_loc <= var->data.location); + last_loc = var->data.location; + unsigned last_slot_location = driver_location + var_size; + if (last_slot_location > location) { + unsigned num_unallocated_slots = last_slot_location - location; + unsigned first_unallocated_slot = var_size - num_unallocated_slots; + for (unsigned i = first_unallocated_slot; i < num_unallocated_slots; i++) { + assigned_locations[var->data.location + i] = location; + location++; + } + } + continue; + } + + for (unsigned i = 0; i < var_size; i++) { + assigned_locations[var->data.location + i] = location + i; + } + + var->data.driver_location = location; + location += var_size; + } + + if (last_partial) + location++; + + *size = location; +} +