nir/spirv: Handle builtins in OpAccessChain
Previously, we were trying to handle them later when loading. However, at that point, you've already lost information and it's harder to handle certain corner-cases. In particular, if you have a shader that does gl_PerVertex.gl_Position.x = foo we have trouble because we see the .x and we don't know that we're in gl_Position. If we, instead, handle it in OpAccessChain, we have all the information we need and we can silently re-direct it to the appropreate variable. This also lets us delete some code which is a nice side-effect.
This commit is contained in:
+12
-49
@@ -854,44 +854,6 @@ get_builtin_variable(struct vtn_builder *b,
|
||||
return var;
|
||||
}
|
||||
|
||||
static void
|
||||
vtn_builtin_load(struct vtn_builder *b,
|
||||
struct vtn_ssa_value *val,
|
||||
SpvBuiltIn builtin)
|
||||
{
|
||||
assert(glsl_type_is_vector_or_scalar(val->type));
|
||||
|
||||
nir_variable *var = get_builtin_variable(b, val->type, builtin);
|
||||
|
||||
nir_intrinsic_instr *load =
|
||||
nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var);
|
||||
nir_ssa_dest_init(&load->instr, &load->dest,
|
||||
glsl_get_vector_elements(val->type), NULL);
|
||||
|
||||
load->variables[0] = nir_deref_var_create(load, var);
|
||||
load->num_components = glsl_get_vector_elements(val->type);
|
||||
nir_builder_instr_insert(&b->nb, &load->instr);
|
||||
val->def = &load->dest.ssa;
|
||||
}
|
||||
|
||||
static void
|
||||
vtn_builtin_store(struct vtn_builder *b,
|
||||
struct vtn_ssa_value *val,
|
||||
SpvBuiltIn builtin)
|
||||
{
|
||||
assert(glsl_type_is_vector_or_scalar(val->type));
|
||||
|
||||
nir_variable *var = get_builtin_variable(b, val->type, builtin);
|
||||
|
||||
nir_intrinsic_instr *store =
|
||||
nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_var);
|
||||
|
||||
store->variables[0] = nir_deref_var_create(store, var);
|
||||
store->num_components = glsl_get_vector_elements(val->type);
|
||||
store->src[0] = nir_src_for_ssa(val->def);
|
||||
nir_builder_instr_insert(&b->nb, &store->instr);
|
||||
}
|
||||
|
||||
static struct vtn_ssa_value *
|
||||
_vtn_variable_load(struct vtn_builder *b,
|
||||
nir_deref_var *src_deref, struct vtn_type *src_type,
|
||||
@@ -900,11 +862,6 @@ _vtn_variable_load(struct vtn_builder *b,
|
||||
struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value);
|
||||
val->type = src_deref_tail->type;
|
||||
|
||||
if (src_type->is_builtin) {
|
||||
vtn_builtin_load(b, val, src_type->builtin);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* The deref tail may contain a deref to select a component of a vector (in
|
||||
* other words, it might not be an actual tail) so we have to save it away
|
||||
* here since we overwrite it later.
|
||||
@@ -976,11 +933,6 @@ _vtn_variable_store(struct vtn_builder *b, struct vtn_type *dest_type,
|
||||
nir_deref_var *dest_deref, nir_deref *dest_deref_tail,
|
||||
struct vtn_ssa_value *src)
|
||||
{
|
||||
if (dest_type->is_builtin) {
|
||||
vtn_builtin_store(b, src, dest_type->builtin);
|
||||
return;
|
||||
}
|
||||
|
||||
nir_deref *old_child = dest_deref_tail->child;
|
||||
|
||||
if (glsl_type_is_vector_or_scalar(src->type)) {
|
||||
@@ -1410,7 +1362,18 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
|
||||
default:
|
||||
unreachable("Invalid type for deref");
|
||||
}
|
||||
tail = tail->child;
|
||||
|
||||
if (deref_type->is_builtin) {
|
||||
/* If we encounter a builtin, we throw away the ress of the
|
||||
* access chain, jump to the builtin, and keep building.
|
||||
*/
|
||||
nir_variable *builtin = get_builtin_variable(b, deref_type->type,
|
||||
deref_type->builtin);
|
||||
val->deref = nir_deref_var_create(b, builtin);
|
||||
tail = &val->deref->deref;
|
||||
} else {
|
||||
tail = tail->child;
|
||||
}
|
||||
}
|
||||
|
||||
/* For uniform blocks, we don't resolve the access chain until we
|
||||
|
||||
Reference in New Issue
Block a user