diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index a58c136399b..33cc82e9d93 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -3416,6 +3416,16 @@ typedef enum { nir_divergence_multiple_workgroup_per_compute_subgroup = (1 << 5), } nir_divergence_options; +typedef enum { + nir_pack_varying_interp_mode_none = (1 << 0), + nir_pack_varying_interp_mode_smooth = (1 << 1), + nir_pack_varying_interp_mode_flat = (1 << 2), + nir_pack_varying_interp_mode_noperspective = (1 << 3), + nir_pack_varying_interp_loc_sample = (1 << 16), + nir_pack_varying_interp_loc_centroid = (1 << 17), + nir_pack_varying_interp_loc_center = (1 << 18), +} nir_pack_varying_options; + /** An instruction filtering callback * * Returns true if the instruction should be processed and false otherwise. @@ -3777,6 +3787,13 @@ typedef struct nir_shader_compiler_options { nir_lower_int64_options lower_int64_options; nir_lower_doubles_options lower_doubles_options; nir_divergence_options divergence_analysis_options; + + /** + * Support pack varyings with different interpolation location + * (center, centroid, sample) and mode (flat, noperspective, smooth) + * into same slot. + */ + nir_pack_varying_options pack_varying_options; } nir_shader_compiler_options; typedef struct nir_shader { diff --git a/src/compiler/nir/nir_linking_helpers.c b/src/compiler/nir/nir_linking_helpers.c index be4144ade86..2c2c342a758 100644 --- a/src/compiler/nir/nir_linking_helpers.c +++ b/src/compiler/nir/nir_linking_helpers.c @@ -670,12 +670,60 @@ gather_varying_component_info(nir_shader *producer, nir_shader *consumer, } } +static bool +allow_pack_interp_type(nir_pack_varying_options options, int type) +{ + int sel; + + switch (type) { + case INTERP_MODE_NONE: + sel = nir_pack_varying_interp_mode_none; + break; + case INTERP_MODE_SMOOTH: + sel = nir_pack_varying_interp_mode_smooth; + break; + case INTERP_MODE_FLAT: + sel = nir_pack_varying_interp_mode_flat; + break; + case INTERP_MODE_NOPERSPECTIVE: + sel = nir_pack_varying_interp_mode_noperspective; + break; + default: + return false; + } + + return options & sel; +} + +static bool +allow_pack_interp_loc(nir_pack_varying_options options, int loc) +{ + int sel; + + switch (loc) { + case INTERPOLATE_LOC_SAMPLE: + sel = nir_pack_varying_interp_loc_sample; + break; + case INTERPOLATE_LOC_CENTROID: + sel = nir_pack_varying_interp_loc_centroid; + break; + case INTERPOLATE_LOC_CENTER: + sel = nir_pack_varying_interp_loc_center; + break; + default: + return false; + } + + return options & sel; +} + static void assign_remap_locations(struct varying_loc (*remap)[4], struct assigned_comps *assigned_comps, struct varying_component *info, unsigned *cursor, unsigned *comp, - unsigned max_location) + unsigned max_location, + nir_pack_varying_options options) { unsigned tmp_cursor = *cursor; unsigned tmp_comp = *comp; @@ -683,21 +731,28 @@ assign_remap_locations(struct varying_loc (*remap)[4], for (; tmp_cursor < max_location; tmp_cursor++) { if (assigned_comps[tmp_cursor].comps) { - /* We can only pack varyings with matching interpolation types, - * interpolation loc must match also. - * TODO: i965 can handle interpolation locations that don't match, - * but the radeonsi nir backend handles everything as vec4s and so - * expects this to be the same for all components. We could make this - * check driver specfific or drop it if NIR ever become the only - * radeonsi backend. - * TODO2: The radeonsi comment above is not true. Only "flat" is per - * vec4 (128-bit granularity), all other interpolation qualifiers are - * per component (16-bit granularity for float16, 32-bit granularity - * otherwise). Each vec4 (128 bits) must be either vec4 or f16vec8. + /* We can only pack varyings with matching precision. */ + if (assigned_comps[tmp_cursor].is_mediump != info->is_mediump) { + tmp_comp = 0; + continue; + } + + /* We can only pack varyings with matching interpolation type + * if driver does not support it. */ - if (assigned_comps[tmp_cursor].interp_type != info->interp_type || - assigned_comps[tmp_cursor].interp_loc != info->interp_loc || - assigned_comps[tmp_cursor].is_mediump != info->is_mediump) { + if (assigned_comps[tmp_cursor].interp_type != info->interp_type && + (!allow_pack_interp_type(options, assigned_comps[tmp_cursor].interp_type) || + !allow_pack_interp_type(options, info->interp_type))) { + tmp_comp = 0; + continue; + } + + /* We can only pack varyings with matching interpolation location + * if driver does not support it. + */ + if (assigned_comps[tmp_cursor].interp_loc != info->interp_loc && + (!allow_pack_interp_loc(options, assigned_comps[tmp_cursor].interp_loc) || + !allow_pack_interp_loc(options, info->interp_loc))) { tmp_comp = 0; continue; } @@ -764,6 +819,8 @@ compact_components(nir_shader *producer, nir_shader *consumer, qsort(varying_comp_info, varying_comp_info_size, sizeof(struct varying_component), cmp_varying_component); + nir_pack_varying_options options = consumer->options->pack_varying_options; + unsigned cursor = 0; unsigned comp = 0; @@ -783,10 +840,12 @@ compact_components(nir_shader *producer, nir_shader *consumer, } assign_remap_locations(remap, assigned_comps, info, - &cursor, &comp, MAX_VARYINGS_INCL_PATCH); + &cursor, &comp, MAX_VARYINGS_INCL_PATCH, + options); } else { assign_remap_locations(remap, assigned_comps, info, - &cursor, &comp, MAX_VARYING); + &cursor, &comp, MAX_VARYING, + options); /* Check if we failed to assign a remap location. This can happen if * for example there are a bunch of unmovable components with @@ -799,7 +858,8 @@ compact_components(nir_shader *producer, nir_shader *consumer, cursor = 0; comp = 0; assign_remap_locations(remap, assigned_comps, info, - &cursor, &comp, MAX_VARYING); + &cursor, &comp, MAX_VARYING, + options); } } }