summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Graunke <kenneth@whitecape.org>2015-10-07 12:44:08 -0700
committerKenneth Graunke <kenneth@whitecape.org>2015-11-04 10:18:56 -0800
commitfd8549994d152461df034ea03c168a37bcb279be (patch)
tree1323b20921bd652be1f724f72ad26552f257445b
parent666945df2d6853dfd032a5075d2f552618e541d8 (diff)
NIR TCS OUTPUT SHADOWING
▄▄ ▄▄▄▄ ▄▄ ▄▄ ██ ██▀▀▀ ██ ██ ▄███▄██ ▄████▄ ██▄████ ▄████▄ ███████ ▄▄█████▄ ██ ██ ██▀ ▀██ ██▄▄▄▄██ ██▀ ██▄▄▄▄██ ██ ██▄▄▄▄ ▀ ██ ██ ██ ██ ██▀▀▀▀▀▀ ██ ██▀▀▀▀▀▀ ██ ▀▀▀▀██▄ ▀▀ ▀▀ ▀██▄▄███ ▀██▄▄▄▄█ ██ ▀██▄▄▄▄█ ██ █▄▄▄▄▄██ ▄▄ ▄▄ ▀▀▀ ▀▀ ▀▀▀▀▀ ▀▀ ▀▀▀▀▀ ▀▀ ▀▀▀▀▀▀ ▀▀ ▀▀ ▄▄ ██ ▄▄ ▄█▀ ██ ██ ██ ██ ▀█▄ ▀▀ ██ ▀▀ but I think it probably works...probably...probably
-rw-r--r--src/glsl/nir/nir_lower_outputs_to_temporaries.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/glsl/nir/nir_lower_outputs_to_temporaries.c b/src/glsl/nir/nir_lower_outputs_to_temporaries.c
index 80f43951b5..1fbf49a038 100644
--- a/src/glsl/nir/nir_lower_outputs_to_temporaries.c
+++ b/src/glsl/nir/nir_lower_outputs_to_temporaries.c
@@ -54,6 +54,20 @@ emit_output_copies(nir_cursor cursor, struct lower_outputs_state *state)
copy->variables[0] = nir_deref_var_create(copy, output);
copy->variables[1] = nir_deref_var_create(copy, temp);
+ if (output->type != temp->type) {
+ nir_intrinsic_instr *invoc_id =
+ nir_intrinsic_instr_create(state->shader,
+ nir_intrinsic_load_invocation_id);
+ nir_ssa_dest_init(&invoc_id->instr, &invoc_id->dest, 1, NULL);
+ nir_instr_insert(cursor, &invoc_id->instr);
+
+ nir_deref_array *array = nir_deref_array_create(copy->variables[0]);
+ copy->variables[0]->deref.child = &array->deref;
+ array->deref_array_type = nir_deref_array_type_indirect;
+ array->deref.type = temp->type;
+ array->indirect = nir_src_for_ssa(&invoc_id->dest.ssa);
+ }
+
nir_instr_insert(cursor, &copy->instr);
}
}
@@ -73,6 +87,60 @@ emit_output_copies_block(nir_block *block, void *state)
return true;
}
+/**
+ * Returns true if \p instr is a load_var of the gl_InvocationID variable.
+ */
+static bool
+is_load_invocation_id(nir_instr *instr)
+{
+ if (instr->type != nir_instr_type_intrinsic)
+ return false;
+
+ nir_intrinsic_instr *load = nir_instr_as_intrinsic(instr);
+
+ return load->intrinsic == nir_intrinsic_load_var &&
+ load->variables[0]->var->data.mode == nir_var_system_value &&
+ load->variables[0]->var->data.location == SYSTEM_VALUE_INVOCATION_ID;
+}
+
+static bool
+strip_array_deref_from_per_vertex_tcs_outputs(nir_block *block, void *state)
+{
+ nir_foreach_instr(block, instr) {
+ if (instr->type != nir_instr_type_intrinsic)
+ continue;
+
+ nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
+
+ if (intrin->intrinsic != nir_intrinsic_load_var &&
+ intrin->intrinsic != nir_intrinsic_store_var &&
+ intrin->intrinsic != nir_intrinsic_copy_var)
+ continue;
+
+ /* XXX: copy var? */
+
+ nir_deref_var *deref_var = intrin->variables[0];
+ nir_variable *var = deref_var->var;
+
+ if (var->data.patch || var->data.mode != nir_var_global ||
+ strstr(var->name, "@out-temp") == NULL)
+ continue;
+
+ assert(deref_var->deref.child->deref_type == nir_deref_type_array);
+ nir_deref_array *arr = nir_deref_as_array(deref_var->deref.child);
+ if (arr->deref_array_type == nir_deref_array_type_indirect &&
+ arr->indirect.is_ssa &&
+ is_load_invocation_id(arr->indirect.ssa->parent_instr)) {
+ /* This is shadow[gl_InvocationID]; strip the array dereference. */
+
+ deref_var->deref.child = arr->deref.child;
+ deref_var->deref.type = glsl_get_array_element(deref_var->deref.type);
+ list_del(&arr->indirect.use_link);
+ }
+ }
+ return true;
+}
+
void
nir_lower_outputs_to_temporaries(nir_shader *shader)
{
@@ -99,6 +167,13 @@ nir_lower_outputs_to_temporaries(nir_shader *shader)
temp->data.mode = nir_var_global;
temp->constant_initializer = NULL;
+ /* Per-vertex tessellation control outputs are arrays, but we only
+ * need to shadow one element: output[gl_InvocationID]. Drop the
+ * array.
+ */
+ if (shader->stage == MESA_SHADER_TESS_CTRL && !temp->data.patch)
+ temp->type = glsl_get_array_element(temp->type);
+
exec_list_push_tail(&shader->outputs, &output->node);
}
@@ -106,6 +181,12 @@ nir_lower_outputs_to_temporaries(nir_shader *shader)
if (overload->impl == NULL)
continue;
+ if (shader->stage == MESA_SHADER_TESS_CTRL) {
+ nir_foreach_block(overload->impl,
+ strip_array_deref_from_per_vertex_tcs_outputs,
+ NULL);
+ }
+
if (shader->stage == MESA_SHADER_GEOMETRY) {
/* For geometry shaders, we have to emit the output copies right
* before each EmitVertex call.