zink: handle direct xfb output from output variables
authorMike Blumenkrantz <michael.blumenkrantz@gmail.com>
Wed, 24 Feb 2021 20:00:22 +0000 (15:00 -0500)
committerMarge Bot <eric+marge@anholt.net>
Tue, 9 Mar 2021 02:52:20 +0000 (02:52 +0000)
if an entire variable is being dumped into an xfb buffer, there's no need
to create an explicit xfb variable to copy the value into, and instead
the xfb attributes can just be set normally on the variable

this doesn't work for geometry shaders because outputs are per-vertex

fixes all KHR-GL46.enhanced_layouts xfb tests

Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9271>

src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c
src/gallium/drivers/zink/zink_compiler.c
src/gallium/drivers/zink/zink_compiler.h

index be682c7..7bb5f57 100644 (file)
@@ -621,6 +621,14 @@ emit_output(struct ntv_context *ctx, struct nir_variable *var)
    if (var->data.patch)
       spirv_builder_emit_decoration(&ctx->builder, var_id, SpvDecorationPatch);
 
+   if (var->data.explicit_xfb_buffer) {
+      spirv_builder_emit_offset(&ctx->builder, var_id, var->data.offset);
+      spirv_builder_emit_xfb_buffer(&ctx->builder, var_id, var->data.xfb.buffer);
+      spirv_builder_emit_xfb_stride(&ctx->builder, var_id, var->data.xfb.stride);
+      if (var->data.stream)
+         spirv_builder_emit_stream(&ctx->builder, var_id, var->data.stream);
+   }
+
    _mesa_hash_table_insert(ctx->vars, var, (void *)(intptr_t)var_id);
 
    assert(ctx->num_entry_ifaces < ARRAY_SIZE(ctx->entry_ifaces));
@@ -1252,6 +1260,8 @@ emit_so_info(struct ntv_context *ctx, const struct zink_so_info *so_info)
 {
    unsigned output = 0;
    for (unsigned i = 0; i < so_info->so_info.num_outputs; i++) {
+      if (so_info->skip[i])
+         continue;
       struct pipe_stream_output so_output = so_info->so_info.output[i];
       unsigned slot = so_info->so_info_slots[i] << 2 | so_output.start_component;
       SpvId out_type = get_output_type(ctx, slot, so_output.num_components);
@@ -1299,6 +1309,8 @@ emit_so_outputs(struct ntv_context *ctx,
                 const struct zink_so_info *so_info)
 {
    for (unsigned i = 0; i < so_info->so_info.num_outputs; i++) {
+      if (so_info->skip[i])
+         continue;
       uint32_t components[NIR_MAX_VEC_COMPONENTS];
       unsigned slot = so_info->so_info_slots[i];
       struct pipe_stream_output so_output = so_info->so_info.output[i];
index 620bc43..38e95c1 100644 (file)
@@ -402,13 +402,13 @@ check_psiz(struct nir_shader *s)
    return false;
 }
 
-/* semi-copied from iris */
 static void
 update_so_info(struct zink_shader *sh,
                uint64_t outputs_written, bool have_psiz)
 {
    uint8_t reverse_map[64] = {};
    unsigned slot = 0;
+   /* semi-copied from iris */
    while (outputs_written) {
       int bit = u_bit_scan64(&outputs_written);
       /* PSIZ from nir_lower_point_size_mov breaks stream output, so always skip it */
@@ -417,8 +417,36 @@ update_so_info(struct zink_shader *sh,
       reverse_map[slot++] = bit;
    }
 
+   nir_foreach_shader_out_variable(var, sh->nir)
+      var->data.explicit_xfb_buffer = 0;
+
+   bool inlined[64] = {0};
    for (unsigned i = 0; i < sh->streamout.so_info.num_outputs; i++) {
       struct pipe_stream_output *output = &sh->streamout.so_info.output[i];
+      unsigned slot = reverse_map[output->register_index];
+      if ((sh->nir->info.stage != MESA_SHADER_GEOMETRY || util_bitcount(sh->nir->info.gs.active_stream_mask) == 1) &&
+          !output->start_component) {
+         nir_variable *var = NULL;
+         while (!var)
+            var = nir_find_variable_with_location(sh->nir, nir_var_shader_out, slot--);
+         slot++;
+         if (inlined[slot]) {
+            sh->streamout.skip[i] = true;
+            continue;
+         }
+         assert(var && var->data.location == slot);
+         /* if this is the entire variable, try to blast it out during the initial declaration */
+         if (glsl_get_components(var->type) == output->num_components) {
+            var->data.explicit_xfb_buffer = 1;
+            var->data.xfb.buffer = output->output_buffer;
+            var->data.xfb.stride = sh->streamout.so_info.stride[output->output_buffer] * 4;
+            var->data.offset = output->dst_offset * 4;
+            var->data.stream = output->stream;
+            sh->streamout.skip[i] = true;
+            inlined[slot] = true;
+            continue;
+         }
+      }
       /* Map Gallium's condensed "slots" back to real VARYING_SLOT_* enums */
       sh->streamout.so_info_slots[i] = reverse_map[output->register_index];
    }
index e61d8ae..bc2c57d 100644 (file)
@@ -51,6 +51,7 @@ struct tgsi_token;
 struct zink_so_info {
    struct pipe_stream_output_info so_info;
    unsigned so_info_slots[PIPE_MAX_SO_OUTPUTS];
+   bool skip[PIPE_MAX_SO_OUTPUTS];
    bool have_xfb;
 };