X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fnir%2Fnir_lower_clip_cull_distance_arrays.c;h=7587bb26e094c52371fe0071b1700b6876ada511;hb=8e2009c4481434f1b97713d8a0ec193fdccb65a6;hp=5a89eddc271e6638ed847f2ed34223c9767d6cfe;hpb=9a179f2db090bfb5643779ac84c2b61fe525a780;p=mesa.git diff --git a/src/compiler/nir/nir_lower_clip_cull_distance_arrays.c b/src/compiler/nir/nir_lower_clip_cull_distance_arrays.c index 5a89eddc271..7587bb26e09 100644 --- a/src/compiler/nir/nir_lower_clip_cull_distance_arrays.c +++ b/src/compiler/nir/nir_lower_clip_cull_distance_arrays.c @@ -27,10 +27,10 @@ /** * @file * - * This pass combines separate clip and cull distance arrays into a - * single array that contains both. Clip distances come first, then - * cull distances. It also populates nir_shader_info with the size - * of the original arrays so the driver knows which are which. + * This pass combines clip and cull distance arrays in separate locations and + * colocates them both in VARYING_SLOT_CLIP_DIST0. It does so by maintaining + * two arrays but making them compact and using location_frac to stack them on + * top of each other. */ /** @@ -48,7 +48,7 @@ get_unwrapped_array_length(nir_shader *nir, nir_variable *var) * array length. */ const struct glsl_type *type = var->type; - if (nir_is_per_vertex_io(var, nir->stage)) + if (nir_is_per_vertex_io(var, nir->info.stage)) type = glsl_get_array_element(type); assert(glsl_type_is_array(type)); @@ -56,72 +56,7 @@ get_unwrapped_array_length(nir_shader *nir, nir_variable *var) return glsl_get_length(type); } -/** - * Update the type of the combined array (including interface block nesting). - */ -static void -update_type(nir_variable *var, gl_shader_stage stage, unsigned length) -{ - const struct glsl_type *type = glsl_array_type(glsl_float_type(), length); - - if (nir_is_per_vertex_io(var, stage)) - type = glsl_array_type(type, glsl_get_length(var->type)); - - var->type = type; -} - -/** - * Rewrite any clip/cull distances to refer to the new combined array. - */ -static void -rewrite_references(nir_instr *instr, - nir_variable *combined, - unsigned cull_offset) -{ - if (instr->type != nir_instr_type_intrinsic) - return; - - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - - /* copy_var needs to be lowered to load/store before calling this pass */ - assert(intrin->intrinsic != nir_intrinsic_copy_var); - - if (intrin->intrinsic != nir_intrinsic_load_var && - intrin->intrinsic != nir_intrinsic_store_var) - return; - - nir_deref_var *var_ref = intrin->variables[0]; - if (var_ref->var->data.mode != combined->data.mode) - return; - - if (var_ref->var->data.location != VARYING_SLOT_CLIP_DIST0 && - var_ref->var->data.location != VARYING_SLOT_CULL_DIST0) - return; - - /* Update types along the deref chain */ - const struct glsl_type *type = combined->type; - nir_deref *deref = &var_ref->deref; - while (deref) { - deref->type = type; - deref = deref->child; - type = glsl_get_array_element(type); - } - - /* For cull distances, add an offset to the array index */ - if (var_ref->var->data.location == VARYING_SLOT_CULL_DIST0) { - nir_deref *tail = nir_deref_tail(&intrin->variables[0]->deref); - nir_deref_array *array_ref = nir_deref_as_array(tail); - - array_ref->base_offset += cull_offset; - } - - /* Point the deref at the combined array */ - var_ref->var = combined; - - /* There's no need to update writemasks; it's a scalar array. */ -} - -static void +static bool combine_clip_cull(nir_shader *nir, struct exec_list *vars, bool store_info) @@ -137,52 +72,73 @@ combine_clip_cull(nir_shader *nir, cull = var; } + if (!cull && !clip) { + /* If this is run after optimizations and the variables have been + * eliminated, we should update the shader info, because no other + * place does that. + */ + if (store_info) { + nir->info.clip_distance_array_size = 0; + nir->info.cull_distance_array_size = 0; + } + return false; + } + + if (!cull && clip) { + /* The GLSL IR lowering pass must have converted these to vectors */ + if (!clip->data.compact) + return false; + + /* If this pass has already run, don't repeat. We would think that + * the combined clip/cull distance array was clip-only and mess up. + */ + if (clip->data.how_declared == nir_var_hidden) + return false; + } + const unsigned clip_array_size = get_unwrapped_array_length(nir, clip); const unsigned cull_array_size = get_unwrapped_array_length(nir, cull); if (store_info) { - nir->info->clip_distance_array_size = clip_array_size; - nir->info->cull_distance_array_size = cull_array_size; + nir->info.clip_distance_array_size = clip_array_size; + nir->info.cull_distance_array_size = cull_array_size; } - if (clip) - clip->data.compact = true; - - if (cull) - cull->data.compact = true; - - if (cull_array_size > 0) { - if (clip_array_size == 0) { - /* No clip distances, just change the cull distance location */ - cull->data.location = VARYING_SLOT_CLIP_DIST0; - } else { - /* Turn the ClipDistance array into a combined one */ - update_type(clip, nir->stage, clip_array_size + cull_array_size); - - /* Rewrite CullDistance to reference the combined array */ - nir_foreach_function(function, nir) { - if (function->impl) { - nir_foreach_block(block, function->impl) { - nir_foreach_instr(instr, block) { - rewrite_references(instr, clip, clip_array_size); - } - } - } - } - - /* Delete the old CullDistance variable */ - exec_node_remove(&cull->node); - ralloc_free(cull); + if (clip) { + assert(clip->data.compact); + clip->data.how_declared = nir_var_hidden; + } + + if (cull) { + assert(cull->data.compact); + cull->data.how_declared = nir_var_hidden; + cull->data.location = VARYING_SLOT_CLIP_DIST0 + clip_array_size / 4; + cull->data.location_frac = clip_array_size % 4; + } + + nir_foreach_function(function, nir) { + if (function->impl) { + nir_metadata_preserve(function->impl, + nir_metadata_block_index | + nir_metadata_dominance | + nir_metadata_live_ssa_defs | + nir_metadata_loop_analysis); } } + + return true; } -void +bool nir_lower_clip_cull_distance_arrays(nir_shader *nir) { - if (nir->stage <= MESA_SHADER_GEOMETRY) - combine_clip_cull(nir, &nir->outputs, true); + bool progress = false; + + if (nir->info.stage <= MESA_SHADER_GEOMETRY) + progress |= combine_clip_cull(nir, &nir->outputs, true); + + if (nir->info.stage > MESA_SHADER_VERTEX) + progress |= combine_clip_cull(nir, &nir->inputs, false); - if (nir->stage > MESA_SHADER_VERTEX) - combine_clip_cull(nir, &nir->inputs, false); + return progress; }