Mesa (main): v3dv: inject a custom passthrough geometry shader for multiview pipelines
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Tue Jul 27 07:45:58 UTC 2021
Module: Mesa
Branch: main
Commit: 5872c7ca7ba79f5e5bf8824ee474b30fa9c12948
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=5872c7ca7ba79f5e5bf8824ee474b30fa9c12948
Author: Iago Toral Quiroga <itoral at igalia.com>
Date: Fri Jul 23 12:42:59 2021 +0200
v3dv: inject a custom passthrough geometry shader for multiview pipelines
This allows us to use layered rendering to broadcast draw calls to the
appropriate views (layers).
Reviewed-by: Alejandro Piñeiro <apinheiro at igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12034>
---
src/broadcom/vulkan/v3dv_pipeline.c | 178 +++++++++++++++++++++++++++++++++++-
src/broadcom/vulkan/v3dv_private.h | 1 +
2 files changed, 177 insertions(+), 2 deletions(-)
diff --git a/src/broadcom/vulkan/v3dv_pipeline.c b/src/broadcom/vulkan/v3dv_pipeline.c
index 15f87fbcc59..370a4f9ccd6 100644
--- a/src/broadcom/vulkan/v3dv_pipeline.c
+++ b/src/broadcom/vulkan/v3dv_pipeline.c
@@ -34,6 +34,7 @@
#include "nir/nir_serialize.h"
#include "util/u_atomic.h"
+#include "util/u_prim.h"
#include "vulkan/util/vk_format.h"
@@ -2060,6 +2061,8 @@ pipeline_populate_graphics_key(struct v3dv_pipeline *pipeline,
key->va_swap_rb_mask |= 1 << (VERT_ATTRIB_GENERIC0 + desc->location);
}
+ assert(pipeline->subpass);
+ key->has_multiview = pipeline->subpass->view_mask != 0;
}
static void
@@ -2107,8 +2110,11 @@ v3dv_pipeline_shared_data_new_empty(const unsigned char sha1_key[20],
continue;
}
- if (stage == BROADCOM_SHADER_GEOMETRY && !pipeline->gs)
- continue;
+ if (stage == BROADCOM_SHADER_GEOMETRY && !pipeline->gs) {
+ /* We always inject a custom GS if we have multiview */
+ if (!pipeline->subpass->view_mask)
+ continue;
+ }
struct v3dv_descriptor_maps *new_maps =
vk_zalloc2(&pipeline->device->vk.alloc, NULL,
@@ -2145,6 +2151,165 @@ fail:
return NULL;
}
+static uint32_t
+multiview_gs_input_primitive_from_pipeline(struct v3dv_pipeline *pipeline)
+{
+ switch (pipeline->topology) {
+ case PIPE_PRIM_POINTS:
+ return GL_POINTS;
+ case PIPE_PRIM_LINES:
+ case PIPE_PRIM_LINE_STRIP:
+ return GL_LINES;
+ case PIPE_PRIM_TRIANGLES:
+ case PIPE_PRIM_TRIANGLE_STRIP:
+ case PIPE_PRIM_TRIANGLE_FAN:
+ return GL_TRIANGLES;
+ default:
+ /* Since we don't allow GS with multiview, we can only see non-adjacency
+ * primitives.
+ */
+ unreachable("Unexpected pipeline primitive type");
+ }
+}
+
+static uint32_t
+multiview_gs_output_primitive_from_pipeline(struct v3dv_pipeline *pipeline)
+{
+ switch (pipeline->topology) {
+ case PIPE_PRIM_POINTS:
+ return GL_POINTS;
+ case PIPE_PRIM_LINES:
+ case PIPE_PRIM_LINE_STRIP:
+ return GL_LINE_STRIP;
+ case PIPE_PRIM_TRIANGLES:
+ case PIPE_PRIM_TRIANGLE_STRIP:
+ case PIPE_PRIM_TRIANGLE_FAN:
+ return GL_TRIANGLE_STRIP;
+ default:
+ /* Since we don't allow GS with multiview, we can only see non-adjacency
+ * primitives.
+ */
+ unreachable("Unexpected pipeline primitive type");
+ }
+}
+
+static bool
+pipeline_add_multiview_gs(struct v3dv_pipeline *pipeline,
+ struct v3dv_pipeline_cache *cache,
+ const VkAllocationCallbacks *pAllocator)
+{
+ /* Create the passthrough GS from the VS output interface */
+ pipeline->vs->nir = pipeline_stage_get_nir(pipeline->vs, pipeline, cache);
+ nir_shader *vs_nir = pipeline->vs->nir;
+
+ const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
+ nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY, options,
+ "multiview broadcast gs");
+ nir_shader *nir = b.shader;
+ nir->info.inputs_read = vs_nir->info.outputs_written;
+ nir->info.outputs_written = vs_nir->info.outputs_written |
+ (1ull << VARYING_SLOT_LAYER);
+
+ uint32_t vertex_count = u_vertices_per_prim(pipeline->topology);
+ nir->info.gs.input_primitive =
+ multiview_gs_input_primitive_from_pipeline(pipeline);
+ nir->info.gs.output_primitive =
+ multiview_gs_output_primitive_from_pipeline(pipeline);
+ nir->info.gs.vertices_in = vertex_count;
+ nir->info.gs.vertices_out = nir->info.gs.vertices_in;
+ nir->info.gs.invocations = 1;
+ nir->info.gs.active_stream_mask = 0x1;
+
+ /* Make a list of GS input/output variables from the VS outputs */
+ nir_variable *in_vars[100];
+ nir_variable *out_vars[100];
+ uint32_t var_count = 0;
+ nir_foreach_shader_out_variable(out_vs_var, vs_nir) {
+ char name[8];
+ snprintf(name, ARRAY_SIZE(name), "in_%d", var_count);
+
+ in_vars[var_count] =
+ nir_variable_create(nir, nir_var_shader_in,
+ glsl_array_type(out_vs_var->type, vertex_count, 0),
+ name);
+ in_vars[var_count]->data.location = out_vs_var->data.location;
+ in_vars[var_count]->data.location_frac = out_vs_var->data.location_frac;
+ in_vars[var_count]->data.interpolation = out_vs_var->data.interpolation;
+
+ snprintf(name, ARRAY_SIZE(name), "out_%d", var_count);
+ out_vars[var_count] =
+ nir_variable_create(nir, nir_var_shader_out, out_vs_var->type, name);
+ out_vars[var_count]->data.location = out_vs_var->data.location;
+ out_vars[var_count]->data.interpolation = out_vs_var->data.interpolation;
+
+ var_count++;
+ }
+
+ /* Add the gl_Layer output variable */
+ nir_variable *out_layer =
+ nir_variable_create(nir, nir_var_shader_out, glsl_int_type(),
+ "out_Layer");
+ out_layer->data.location = VARYING_SLOT_LAYER;
+
+ /* Get the view index value that we will write to gl_Layer */
+ nir_ssa_def *layer =
+ nir_load_system_value(&b, nir_intrinsic_load_view_index, 0, 1, 32);
+
+ /* Emit all output vertices */
+ for (uint32_t vi = 0; vi < vertex_count; vi++) {
+ /* Emit all output varyings */
+ for (uint32_t i = 0; i < var_count; i++) {
+ nir_deref_instr *in_value =
+ nir_build_deref_array_imm(&b, nir_build_deref_var(&b, in_vars[i]), vi);
+ nir_copy_deref(&b, nir_build_deref_var(&b, out_vars[i]), in_value);
+ }
+
+ /* Emit gl_Layer write */
+ nir_store_var(&b, out_layer, layer, 0x1);
+
+ nir_emit_vertex(&b, 0);
+ }
+ nir_end_primitive(&b, 0);
+
+ /* Make sure we run our pre-process NIR passes so we produce NIR compatible
+ * with what we expect from SPIR-V modules.
+ */
+ preprocess_nir(nir);
+
+ /* Attach the geometry shader to the pipeline */
+ struct v3dv_device *device = pipeline->device;
+ struct v3dv_physical_device *physical_device =
+ &device->instance->physicalDevice;
+
+ struct v3dv_pipeline_stage *p_stage =
+ vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*p_stage), 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+
+ if (p_stage == NULL) {
+ ralloc_free(nir);
+ return false;
+ }
+
+ p_stage->pipeline = pipeline;
+ p_stage->stage = BROADCOM_SHADER_GEOMETRY;
+ p_stage->entrypoint = "main";
+ p_stage->module = 0;
+ p_stage->nir = nir;
+ pipeline_compute_sha1_from_nir(p_stage->nir, p_stage->shader_sha1);
+ p_stage->program_id = p_atomic_inc_return(&physical_device->next_program_id);
+
+ pipeline->has_gs = true;
+ pipeline->gs = p_stage;
+ pipeline->active_stages |= MESA_SHADER_GEOMETRY;
+
+ pipeline->gs_bin =
+ pipeline_stage_create_binning(pipeline->gs, pAllocator);
+ if (pipeline->gs_bin == NULL)
+ return false;
+
+ return true;
+}
+
/*
* It compiles a pipeline. Note that it also allocate internal object, but if
* some allocations success, but other fails, the method is not freeing the
@@ -2260,6 +2425,15 @@ pipeline_compile_graphics(struct v3dv_pipeline *pipeline,
pipeline->active_stages |= MESA_SHADER_FRAGMENT;
}
+ /* If multiview is enabled, we inject a custom passthrough geometry shader
+ * to broadcast draw calls to the appropriate views.
+ */
+ assert(!pipeline->subpass->view_mask || (!pipeline->has_gs && !pipeline->gs));
+ if (pipeline->subpass->view_mask) {
+ if (!pipeline_add_multiview_gs(pipeline, cache, pAllocator))
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+
/* First we try to get the variants from the pipeline cache */
struct v3dv_pipeline_key pipeline_key;
pipeline_populate_graphics_key(pipeline, &pipeline_key, pCreateInfo);
diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h
index c6fa66b134b..5d2549a6319 100644
--- a/src/broadcom/vulkan/v3dv_private.h
+++ b/src/broadcom/vulkan/v3dv_private.h
@@ -274,6 +274,7 @@ struct v3dv_pipeline_key {
} color_fmt[V3D_MAX_DRAW_BUFFERS];
uint8_t f32_color_rb;
uint32_t va_swap_rb_mask;
+ bool has_multiview;
};
struct v3dv_pipeline_cache_stats {
More information about the mesa-commit
mailing list