aboutsummaryrefslogtreecommitdiffstats
path: root/src/broadcom/compiler/vir.c
diff options
context:
space:
mode:
authorIago Toral Quiroga <[email protected]>2019-10-28 13:24:44 +0100
committerIago Toral Quiroga <[email protected]>2019-12-16 08:42:37 +0100
commit5d578c27cecb4682074778b90b3e4d57a5cc0ebe (patch)
treeca20b5f252aafc91e82b63553904c27e8a445911 /src/broadcom/compiler/vir.c
parentf63750accf99ff0f8503f7196399ad4e0e11befa (diff)
v3d: add initial compiler plumbing for geometry shaders
Most of the relevant work happens in the v3d_nir_lower_io. Since geometry shaders can write any number of output vertices, this pass injects a few variables into the shader code to keep track of things like the number of vertices emitted or the offsets into the VPM of the current vertex output, etc. This is also where we handle EmitVertex() and EmitPrimitive() intrinsics. The geometry shader VPM output layout has a specific structure with a 32-bit general header, then another 32-bit header slot for each output vertex, and finally the actual vertex data. When vertex shaders are paired with geometry shaders we also need to consider the following: - Only geometry shaders emit fixed function outputs. - The coordinate shader used for the vertex stage during binning must not drop varyings other than those used by transform feedback, since these may be read by the binning GS. v2: - Use MAX3 instead of a chain of MAX2 (Alejandro). - Make all loop variables unsigned in ntq_setup_gs_inputs (Alejandro) - Update comment in IO owering so it includes the GS stage (Alejandro) Reviewed-by: Alejandro PiƱeiro <[email protected]>
Diffstat (limited to 'src/broadcom/compiler/vir.c')
-rw-r--r--src/broadcom/compiler/vir.c119
1 files changed, 107 insertions, 12 deletions
diff --git a/src/broadcom/compiler/vir.c b/src/broadcom/compiler/vir.c
index 340cda903e9..dc966bc80ca 100644
--- a/src/broadcom/compiler/vir.c
+++ b/src/broadcom/compiler/vir.c
@@ -23,6 +23,7 @@
#include "broadcom/common/v3d_device_info.h"
#include "v3d_compiler.h"
+#include "util/u_prim.h"
int
vir_get_nsrc(struct qinst *inst)
@@ -661,6 +662,28 @@ v3d_vs_set_prog_data(struct v3d_compile *c,
}
static void
+v3d_gs_set_prog_data(struct v3d_compile *c,
+ struct v3d_gs_prog_data *prog_data)
+{
+ prog_data->num_inputs = c->num_inputs;
+ memcpy(prog_data->input_slots, c->input_slots,
+ c->num_inputs * sizeof(*c->input_slots));
+
+ /* gl_PrimitiveIdIn is written by the GBG into the first word of the
+ * VPM output header automatically and the shader will overwrite
+ * it after reading it if necessary, so it doesn't add to the VPM
+ * size requirements.
+ */
+ prog_data->uses_pid = (c->s->info.system_values_read &
+ (1ull << SYSTEM_VALUE_PRIMITIVE_ID));
+
+ /* Output segment size is in sectors (8 rows of 32 bits per channel) */
+ prog_data->vpm_output_size = align(c->vpm_output_size, 8) / 8;
+
+ prog_data->out_prim_type = c->s->info.gs.output_primitive;
+}
+
+static void
v3d_set_fs_prog_data_inputs(struct v3d_compile *c,
struct v3d_fs_prog_data *prog_data)
{
@@ -714,13 +737,21 @@ v3d_set_prog_data(struct v3d_compile *c,
v3d_set_prog_data_uniforms(c, prog_data);
- if (c->s->info.stage == MESA_SHADER_COMPUTE) {
- v3d_cs_set_prog_data(c, (struct v3d_compute_prog_data *)prog_data);
- } else if (c->s->info.stage == MESA_SHADER_VERTEX) {
+ switch (c->s->info.stage) {
+ case MESA_SHADER_VERTEX:
v3d_vs_set_prog_data(c, (struct v3d_vs_prog_data *)prog_data);
- } else {
- assert(c->s->info.stage == MESA_SHADER_FRAGMENT);
+ break;
+ case MESA_SHADER_GEOMETRY:
+ v3d_gs_set_prog_data(c, (struct v3d_gs_prog_data *)prog_data);
+ break;
+ case MESA_SHADER_FRAGMENT:
v3d_fs_set_prog_data(c, (struct v3d_fs_prog_data *)prog_data);
+ break;
+ case MESA_SHADER_COMPUTE:
+ v3d_cs_set_prog_data(c, (struct v3d_compute_prog_data *)prog_data);
+ break;
+ default:
+ unreachable("unsupported shader stage");
}
}
@@ -772,6 +803,37 @@ v3d_nir_lower_vs_early(struct v3d_compile *c)
}
static void
+v3d_nir_lower_gs_early(struct v3d_compile *c)
+{
+ /* Split our I/O vars and dead code eliminate the unused
+ * components.
+ */
+ NIR_PASS_V(c->s, nir_lower_io_to_scalar_early,
+ nir_var_shader_in | nir_var_shader_out);
+ uint64_t used_outputs[4] = {0};
+ for (int i = 0; i < c->gs_key->num_used_outputs; i++) {
+ int slot = v3d_slot_get_slot(c->gs_key->used_outputs[i]);
+ int comp = v3d_slot_get_component(c->gs_key->used_outputs[i]);
+ used_outputs[comp] |= 1ull << slot;
+ }
+ NIR_PASS_V(c->s, nir_remove_unused_io_vars,
+ &c->s->outputs, used_outputs, NULL); /* demotes to globals */
+ NIR_PASS_V(c->s, nir_lower_global_vars_to_local);
+ v3d_optimize_nir(c->s);
+ NIR_PASS_V(c->s, nir_remove_dead_variables, nir_var_shader_in);
+
+ /* This must go before nir_lower_io */
+ if (c->gs_key->per_vertex_point_size)
+ NIR_PASS_V(c->s, nir_lower_point_size, 1.0f, 0.0f);
+
+ NIR_PASS_V(c->s, nir_lower_io, nir_var_shader_in | nir_var_shader_out,
+ type_size_vec4,
+ (nir_lower_io_options)0);
+ /* clean up nir_lower_io's deref_var remains */
+ NIR_PASS_V(c->s, nir_opt_dce);
+}
+
+static void
v3d_fixup_fs_output_types(struct v3d_compile *c)
{
nir_foreach_variable(var, &c->s->outputs) {
@@ -819,6 +881,18 @@ v3d_nir_lower_fs_early(struct v3d_compile *c)
}
static void
+v3d_nir_lower_gs_late(struct v3d_compile *c)
+{
+ if (c->key->ucp_enables) {
+ NIR_PASS_V(c->s, nir_lower_clip_gs, c->key->ucp_enables,
+ false, NULL);
+ }
+
+ /* Note: GS output scalarizing must happen after nir_lower_clip_gs. */
+ NIR_PASS_V(c->s, nir_lower_io_to_scalar, nir_var_shader_out);
+}
+
+static void
v3d_nir_lower_vs_late(struct v3d_compile *c)
{
if (c->vs_key->clamp_color)
@@ -907,6 +981,10 @@ uint64_t *v3d_compile(const struct v3d_compiler *compiler,
c->vs_key = (struct v3d_vs_key *)key;
prog_data = rzalloc_size(NULL, sizeof(struct v3d_vs_prog_data));
break;
+ case MESA_SHADER_GEOMETRY:
+ c->gs_key = (struct v3d_gs_key *)key;
+ prog_data = rzalloc_size(NULL, sizeof(struct v3d_gs_prog_data));
+ break;
case MESA_SHADER_FRAGMENT:
c->fs_key = (struct v3d_fs_key *)key;
prog_data = rzalloc_size(NULL, sizeof(struct v3d_fs_prog_data));
@@ -919,20 +997,35 @@ uint64_t *v3d_compile(const struct v3d_compiler *compiler,
unreachable("unsupported shader stage");
}
- if (c->s->info.stage == MESA_SHADER_VERTEX) {
+
+ switch (c->s->info.stage) {
+ case MESA_SHADER_VERTEX:
v3d_nir_lower_vs_early(c);
- } else if (c->s->info.stage != MESA_SHADER_COMPUTE) {
- assert(c->s->info.stage == MESA_SHADER_FRAGMENT);
+ break;
+ case MESA_SHADER_GEOMETRY:
+ v3d_nir_lower_gs_early(c);
+ break;
+ case MESA_SHADER_FRAGMENT:
v3d_nir_lower_fs_early(c);
+ break;
+ default:
+ break;
}
v3d_lower_nir(c);
- if (c->s->info.stage == MESA_SHADER_VERTEX) {
+ switch (c->s->info.stage) {
+ case MESA_SHADER_VERTEX:
v3d_nir_lower_vs_late(c);
- } else if (c->s->info.stage != MESA_SHADER_COMPUTE) {
- assert(c->s->info.stage == MESA_SHADER_FRAGMENT);
+ break;
+ case MESA_SHADER_GEOMETRY:
+ v3d_nir_lower_gs_late(c);
+ break;
+ case MESA_SHADER_FRAGMENT:
v3d_nir_lower_fs_late(c);
+ break;
+ default:
+ break;
}
NIR_PASS_V(c->s, v3d_nir_lower_io, c);
@@ -1134,7 +1227,9 @@ const char *
vir_get_stage_name(struct v3d_compile *c)
{
if (c->vs_key && c->vs_key->is_coord)
- return "MESA_SHADER_COORD";
+ return "MESA_SHADER_VERTEX_BIN";
+ else if (c->gs_key && c->gs_key->is_coord)
+ return "MESA_SHADER_GEOMETRY_BIN";
else
return gl_shader_stage_name(c->s->info.stage);
}