diff options
author | Jason Ekstrand <[email protected]> | 2017-10-18 17:59:47 -0700 |
---|---|---|
committer | Jason Ekstrand <[email protected]> | 2017-12-05 22:01:54 -0800 |
commit | ae54a4f84fb6b440d7a8a57651965a4d9eed725b (patch) | |
tree | 21568b592882609868b00555e8d4014c1417075a /src/compiler/spirv/vtn_variables.c | |
parent | f6eb5ce39cb80f321fedd76d41c638e3d98e03b3 (diff) |
spirv: Add support for lowering workgroup access to offsets
Before, we always left workgroup variables as shared nir_variables and
let the driver call nir_lower_io. This adds an option to do the
lowering directly in spirv_to_nir. To do this, we implicitly assign the
variables a std430 layout and then treat them like a UBO or SSBO and
immediately lower all the way to an offset.
As a side-effect, the spirv_to_nir pass now handles variable pointers
for workgroup variables.
Reviewed-by: Kristian H. Kristensen <[email protected]>
Diffstat (limited to 'src/compiler/spirv/vtn_variables.c')
-rw-r--r-- | src/compiler/spirv/vtn_variables.c | 54 |
1 files changed, 47 insertions, 7 deletions
diff --git a/src/compiler/spirv/vtn_variables.c b/src/compiler/spirv/vtn_variables.c index 3369ae05a95..06eab2dc15c 100644 --- a/src/compiler/spirv/vtn_variables.c +++ b/src/compiler/spirv/vtn_variables.c @@ -62,7 +62,9 @@ vtn_pointer_uses_ssa_offset(struct vtn_builder *b, struct vtn_pointer *ptr) { return ptr->mode == vtn_variable_mode_ubo || - ptr->mode == vtn_variable_mode_ssbo; + ptr->mode == vtn_variable_mode_ssbo || + (ptr->mode == vtn_variable_mode_workgroup && + b->options->lower_workgroup_access_to_offsets); } static bool @@ -71,7 +73,9 @@ vtn_pointer_is_external_block(struct vtn_builder *b, { return ptr->mode == vtn_variable_mode_ssbo || ptr->mode == vtn_variable_mode_ubo || - ptr->mode == vtn_variable_mode_push_constant; + ptr->mode == vtn_variable_mode_push_constant || + (ptr->mode == vtn_variable_mode_workgroup && + b->options->lower_workgroup_access_to_offsets); } /* Dereference the given base pointer by the access chain */ @@ -167,7 +171,8 @@ vtn_ssa_offset_pointer_dereference(struct vtn_builder *b, /* We need ptr_type for the stride */ vtn_assert(base->ptr_type); /* This must be a pointer to an actual element somewhere */ - vtn_assert(block_index && offset); + vtn_assert(offset); + vtn_assert(block_index || base->mode == vtn_variable_mode_workgroup); /* We need at least one element in the chain */ vtn_assert(deref_chain->length >= 1); @@ -183,6 +188,7 @@ vtn_ssa_offset_pointer_dereference(struct vtn_builder *b, vtn_assert(!block_index); vtn_assert(base->var); + vtn_assert(base->ptr_type); switch (base->mode) { case vtn_variable_mode_ubo: case vtn_variable_mode_ssbo: @@ -201,6 +207,22 @@ vtn_ssa_offset_pointer_dereference(struct vtn_builder *b, offset = nir_imm_int(&b->nb, 0); break; + case vtn_variable_mode_workgroup: + /* Assign location on first use so that we don't end up bloating SLM + * address space for variables which are never statically used. + */ + if (base->var->shared_location < 0) { + assert(base->ptr_type->length > 0 && base->ptr_type->align > 0); + b->shader->num_shared = vtn_align_u32(b->shader->num_shared, + base->ptr_type->align); + base->var->shared_location = b->shader->num_shared; + b->shader->num_shared += base->ptr_type->length; + } + + block_index = NULL; + offset = nir_imm_int(&b->nb, base->var->shared_location); + break; + default: vtn_fail("Invalid offset pointer mode"); } @@ -837,6 +859,9 @@ vtn_block_load(struct vtn_builder *b, struct vtn_pointer *src) vtn_access_chain_get_offset_size(b, src->chain, src->var->type, &access_offset, &access_size); break; + case vtn_variable_mode_workgroup: + op = nir_intrinsic_load_shared; + break; default: vtn_fail("Invalid block variable mode"); } @@ -861,6 +886,9 @@ vtn_block_store(struct vtn_builder *b, struct vtn_ssa_value *src, case vtn_variable_mode_ssbo: op = nir_intrinsic_store_ssbo; break; + case vtn_variable_mode_workgroup: + op = nir_intrinsic_store_shared; + break; default: vtn_fail("Invalid block variable mode"); } @@ -946,7 +974,8 @@ vtn_variable_store(struct vtn_builder *b, struct vtn_ssa_value *src, struct vtn_pointer *dest) { if (vtn_pointer_is_external_block(b, dest)) { - vtn_assert(dest->mode == vtn_variable_mode_ssbo); + vtn_assert(dest->mode == vtn_variable_mode_ssbo || + dest->mode == vtn_variable_mode_workgroup); vtn_block_store(b, src, dest); } else { _vtn_variable_load_store(b, false, dest, &src); @@ -1526,7 +1555,7 @@ vtn_pointer_to_ssa(struct vtn_builder *b, struct vtn_pointer *ptr) ptr->mode == vtn_variable_mode_ssbo); return nir_vec2(&b->nb, ptr->block_index, ptr->offset); } else { - vtn_fail("Invalid pointer"); + vtn_assert(ptr->mode == vtn_variable_mode_workgroup); return ptr->offset; } } @@ -1555,7 +1584,7 @@ vtn_pointer_from_ssa(struct vtn_builder *b, nir_ssa_def *ssa, ptr->offset = nir_channel(&b->nb, ssa, 1); } else { vtn_assert(ssa->num_components == 1); - unreachable("Invalid pointer"); + vtn_assert(ptr->mode == vtn_variable_mode_workgroup); ptr->block_index = NULL; ptr->offset = ssa; } @@ -1630,7 +1659,6 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, case vtn_variable_mode_global: case vtn_variable_mode_image: case vtn_variable_mode_sampler: - case vtn_variable_mode_workgroup: /* For these, we create the variable normally */ var->var = rzalloc(b->shader, nir_variable); var->var->name = ralloc_strdup(var->var, val->name); @@ -1648,6 +1676,18 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, } break; + case vtn_variable_mode_workgroup: + if (b->options->lower_workgroup_access_to_offsets) { + var->shared_location = -1; + } else { + /* Create the variable normally */ + var->var = rzalloc(b->shader, nir_variable); + var->var->name = ralloc_strdup(var->var, val->name); + var->var->type = var->type->type; + var->var->data.mode = nir_var_shared; + } + break; + case vtn_variable_mode_input: case vtn_variable_mode_output: { /* In order to know whether or not we're a per-vertex inout, we need |