freedreno/ir3: Passthrough TCS support
authorRob Clark <robdclark@chromium.org>
Sat, 22 Oct 2022 18:39:21 +0000 (11:39 -0700)
committerMarge Bot <emma+marge@anholt.net>
Mon, 24 Oct 2022 21:39:38 +0000 (21:39 +0000)
Wire up support for the two intrisics to get default tess levels (which
adds new HS driver params) and add a helper to generate a passthrough
TCS for a given VS.  The passthrough TCS is cached in the VS, indexed by
patch_vertices, as the generated TCS is a function of the VS outputs and
the patch_vertices count.

Signed-off-by: Rob Clark <robdclark@chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19259>

src/freedreno/ir3/ir3_compiler_nir.c
src/freedreno/ir3/ir3_nir.c
src/freedreno/ir3/ir3_shader.c
src/freedreno/ir3/ir3_shader.h

index c6413d8..28eada2 100644 (file)
@@ -2433,6 +2433,16 @@ emit_intrinsic(struct ir3_context *ctx, nir_intrinsic_instr *intr)
       dst[0]->cat6.type = TYPE_U32;
       __ssa_dst(dst[0]);
       break;
+   case nir_intrinsic_load_tess_level_outer_default:
+      for (int i = 0; i < dest_components; i++) {
+         dst[i] = create_driver_param(ctx, IR3_DP_HS_DEFAULT_OUTER_LEVEL_X + i);
+      }
+      break;
+   case nir_intrinsic_load_tess_level_inner_default:
+      for (int i = 0; i < dest_components; i++) {
+         dst[i] = create_driver_param(ctx, IR3_DP_HS_DEFAULT_INNER_LEVEL_X + i);
+      }
+      break;
    case nir_intrinsic_discard_if:
    case nir_intrinsic_discard:
    case nir_intrinsic_demote:
index ca39ece..2669552 100644 (file)
@@ -679,6 +679,8 @@ ir3_nir_lower_variant(struct ir3_shader_variant *so, nir_shader *s)
          progress = true;
          break;
       case MESA_SHADER_TESS_CTRL:
+         NIR_PASS_V(s, nir_lower_io_to_scalar,
+                     nir_var_shader_in | nir_var_shader_out);
          NIR_PASS_V(s, ir3_nir_lower_tess_ctrl, so, so->key.tessellation);
          NIR_PASS_V(s, ir3_nir_lower_to_explicit_input, so);
          progress = true;
@@ -940,6 +942,14 @@ ir3_nir_scan_driver_consts(struct ir3_compiler *compiler, nir_shader *shader, st
                layout->num_driver_params =
                   MAX2(layout->num_driver_params, IR3_DP_DRAWID + 1);
                break;
+            case nir_intrinsic_load_tess_level_outer_default:
+               layout->num_driver_params = MAX2(layout->num_driver_params,
+                                                IR3_DP_HS_DEFAULT_OUTER_LEVEL_W + 1);
+               break;
+            case nir_intrinsic_load_tess_level_inner_default:
+               layout->num_driver_params = MAX2(layout->num_driver_params,
+                                                IR3_DP_HS_DEFAULT_INNER_LEVEL_Y + 1);
+               break;
             default:
                break;
             }
index 7ce121b..049b5d7 100644 (file)
@@ -415,9 +415,58 @@ ir3_shader_get_variant(struct ir3_shader *shader,
    return v;
 }
 
+struct ir3_shader *
+ir3_shader_passthrough_tcs(struct ir3_shader *vs, unsigned patch_vertices)
+{
+   assert(vs->type == MESA_SHADER_VERTEX);
+   assert(patch_vertices > 0);
+   assert(patch_vertices <= 32);
+
+   unsigned n = patch_vertices - 1;
+   if (!vs->vs.passthrough_tcs[n]) {
+      const nir_shader_compiler_options *options =
+            ir3_get_compiler_options(vs->compiler);
+      nir_shader *tcs =
+            nir_create_passthrough_tcs(options, vs->nir, patch_vertices);
+
+      /* Technically it is an internal shader but it is confusing to
+       * not have it show up in debug output
+       */
+      tcs->info.internal = false;
+
+      nir_assign_io_var_locations(tcs, nir_var_shader_in,
+                                  &tcs->num_inputs,
+                                  tcs->info.stage);
+
+      nir_assign_io_var_locations(tcs, nir_var_shader_out,
+                                  &tcs->num_outputs,
+                                  tcs->info.stage);
+
+      NIR_PASS_V(tcs, nir_lower_system_values);
+
+      nir_shader_gather_info(tcs, nir_shader_get_entrypoint(tcs));
+
+      ir3_finalize_nir(vs->compiler, tcs);
+
+      struct ir3_shader_options ir3_options = {};
+
+      vs->vs.passthrough_tcs[n] =
+            ir3_shader_from_nir(vs->compiler, tcs, &ir3_options, NULL);
+
+      vs->vs.passthrough_tcs_compiled |= BITFIELD_BIT(n);
+   }
+
+   return vs->vs.passthrough_tcs[n];
+}
+
 void
 ir3_shader_destroy(struct ir3_shader *shader)
 {
+   if (shader->type == MESA_SHADER_VERTEX) {
+      u_foreach_bit (b, shader->vs.passthrough_tcs_compiled) {
+         ir3_shader_destroy(shader->vs.passthrough_tcs[b]);
+      }
+   }
    ralloc_free(shader->nir);
    mtx_destroy(&shader->variants_lock);
    ralloc_free(shader);
index ddc635e..a97a65a 100644 (file)
@@ -73,6 +73,15 @@ enum ir3_driver_param {
    IR3_DP_UCP7_W = 35,
    IR3_DP_VS_COUNT = 36, /* must be aligned to vec4 */
 
+   /* TCS driver params: */
+   IR3_DP_HS_DEFAULT_OUTER_LEVEL_X = 0,
+   IR3_DP_HS_DEFAULT_OUTER_LEVEL_Y = 1,
+   IR3_DP_HS_DEFAULT_OUTER_LEVEL_Z = 2,
+   IR3_DP_HS_DEFAULT_OUTER_LEVEL_W = 3,
+   IR3_DP_HS_DEFAULT_INNER_LEVEL_X = 4,
+   IR3_DP_HS_DEFAULT_INNER_LEVEL_Y = 5,
+   IR3_DP_HS_COUNT = 8, /* must be aligned to vec4 */
+
    /* fragment shader driver params: */
    IR3_DP_FS_SUBGROUP_SIZE = 0,
 };
@@ -854,6 +863,15 @@ struct ir3_shader {
          unsigned req_input_mem;    /* in dwords */
          unsigned req_local_mem;
       } cs;
+      /* For vertex shaders: */
+      struct {
+         /* If we need to generate a passthrough TCS, it will be a function of
+          * (a) the VS and (b) the # of patch_vertices (max 32), so cache them
+          * in the VS keyed by # of patch_vertices-1.
+          */
+         unsigned passthrough_tcs_compiled;
+         struct ir3_shader *passthrough_tcs[32];
+      } vs;
    };
 
    struct ir3_shader_variant *variants;
@@ -939,6 +957,8 @@ ir3_shader_from_nir(struct ir3_compiler *compiler, nir_shader *nir,
                     struct ir3_stream_output_info *stream_output);
 uint32_t ir3_trim_constlen(struct ir3_shader_variant **variants,
                            const struct ir3_compiler *compiler);
+struct ir3_shader *
+ir3_shader_passthrough_tcs(struct ir3_shader *vs, unsigned patch_vertices);
 void ir3_shader_destroy(struct ir3_shader *shader);
 void ir3_shader_disasm(struct ir3_shader_variant *so, uint32_t *bin, FILE *out);
 uint64_t ir3_shader_outputs(const struct ir3_shader *so);