glsl/nir: adjust sparse texture nir_variable

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14362>
This commit is contained in:
Qiang Yu
2021-12-28 21:11:07 +08:00
parent 3dc950118c
commit a0b6515ec4

View File

@@ -117,6 +117,12 @@ private:
/* map of ir_function_signature -> nir_function_overload */
struct hash_table *overload_table;
/* set of nir_variable hold sparse result */
struct set *sparse_variable_set;
void adjust_sparse_variable(nir_deref_instr *var_deref, const glsl_type *type,
nir_ssa_def *dest);
};
/*
@@ -270,6 +276,7 @@ nir_visitor::nir_visitor(const struct gl_constants *consts, nir_shader *shader)
this->is_global = true;
this->var_table = _mesa_pointer_hash_table_create(NULL);
this->overload_table = _mesa_pointer_hash_table_create(NULL);
this->sparse_variable_set = _mesa_pointer_set_create(NULL);
this->result = NULL;
this->impl = NULL;
this->deref = NULL;
@@ -281,6 +288,7 @@ nir_visitor::~nir_visitor()
{
_mesa_hash_table_destroy(this->var_table, NULL);
_mesa_hash_table_destroy(this->overload_table, NULL);
_mesa_set_destroy(this->sparse_variable_set, NULL);
}
nir_deref_instr *
@@ -433,6 +441,29 @@ nir_visitor::constant_copy(ir_constant *ir, void *mem_ctx)
return ret;
}
void
nir_visitor::adjust_sparse_variable(nir_deref_instr *var_deref, const glsl_type *type,
nir_ssa_def *dest)
{
const glsl_type *texel_type = type->field_type("texel");
assert(texel_type);
assert(var_deref->deref_type == nir_deref_type_var);
nir_variable *var = var_deref->var;
/* Adjust nir_variable type to align with sparse nir instructions.
* Because the nir_variable is created with struct type from ir_variable,
* but sparse nir instructions output with vector dest.
*/
var->type = glsl_type::get_instance(texel_type->get_base_type()->base_type,
dest->num_components, 1);
var_deref->type = var->type;
/* Record the adjusted variable. */
_mesa_set_add(this->sparse_variable_set, var);
}
static unsigned
get_nir_how_declared(unsigned how_declared)
{
@@ -1606,8 +1637,14 @@ nir_visitor::visit(ir_call *ir)
unreachable("not reached");
}
if (ir->return_deref)
nir_store_deref(&b, evaluate_deref(ir->return_deref), ret, ~0);
if (ir->return_deref) {
nir_deref_instr *ret_deref = evaluate_deref(ir->return_deref);
if (op == nir_intrinsic_image_deref_sparse_load)
adjust_sparse_variable(ret_deref, ir->return_deref->type, ret);
nir_store_deref(&b, ret_deref, ret, ~0);
}
return;
}
@@ -1659,12 +1696,13 @@ void
nir_visitor::visit(ir_assignment *ir)
{
unsigned num_components = ir->lhs->type->vector_elements;
unsigned write_mask = ir->write_mask;
b.exact = ir->lhs->variable_referenced()->data.invariant ||
ir->lhs->variable_referenced()->data.precise;
if ((ir->rhs->as_dereference() || ir->rhs->as_constant()) &&
(ir->write_mask == (1 << num_components) - 1 || ir->write_mask == 0)) {
(write_mask == BITFIELD_MASK(num_components) || write_mask == 0)) {
nir_deref_instr *lhs = evaluate_deref(ir->lhs);
nir_deref_instr *rhs = evaluate_deref(ir->rhs);
enum gl_access_qualifier lhs_qualifiers = deref_get_qualifier(lhs);
@@ -1681,13 +1719,25 @@ nir_visitor::visit(ir_assignment *ir)
return;
}
ir_texture *tex = ir->rhs->as_texture();
bool is_sparse = tex && tex->is_sparse;
if (!is_sparse)
assert(ir->rhs->type->is_scalar() || ir->rhs->type->is_vector());
ir->lhs->accept(this);
nir_deref_instr *lhs_deref = this->deref;
nir_ssa_def *src = evaluate_rvalue(ir->rhs);
if (ir->write_mask != (1 << num_components) - 1 && ir->write_mask != 0) {
if (is_sparse) {
adjust_sparse_variable(lhs_deref, tex->type, src);
/* correct component and mask because they are 0 for struct */
num_components = src->num_components;
write_mask = BITFIELD_MASK(num_components);
}
if (write_mask != BITFIELD_MASK(num_components) && write_mask != 0) {
/* GLSL IR will give us the input to the write-masked assignment in a
* single packed vector. So, for example, if the writemask is xzw, then
* we have to swizzle x -> x, y -> z, and z -> w and get the y component
@@ -1696,7 +1746,7 @@ nir_visitor::visit(ir_assignment *ir)
unsigned swiz[4];
unsigned component = 0;
for (unsigned i = 0; i < 4; i++) {
swiz[i] = ir->write_mask & (1 << i) ? component++ : 0;
swiz[i] = write_mask & (1 << i) ? component++ : 0;
}
src = nir_swizzle(&b, src, swiz, num_components);
}
@@ -1704,11 +1754,11 @@ nir_visitor::visit(ir_assignment *ir)
enum gl_access_qualifier qualifiers = deref_get_qualifier(lhs_deref);
if (ir->condition) {
nir_push_if(&b, evaluate_rvalue(ir->condition));
nir_store_deref_with_access(&b, lhs_deref, src, ir->write_mask,
nir_store_deref_with_access(&b, lhs_deref, src, write_mask,
qualifiers);
nir_pop_if(&b, NULL);
} else {
nir_store_deref_with_access(&b, lhs_deref, src, ir->write_mask,
nir_store_deref_with_access(&b, lhs_deref, src, write_mask,
qualifiers);
}
}
@@ -2599,6 +2649,32 @@ nir_visitor::visit(ir_dereference_record *ir)
int field_index = ir->field_idx;
assert(field_index >= 0);
/* sparse texture variable is a struct for ir_variable, but it has been
* converted to a vector for nir_variable.
*/
if (this->deref->deref_type == nir_deref_type_var &&
_mesa_set_search(this->sparse_variable_set, this->deref->var)) {
nir_ssa_def *load = nir_load_deref(&b, this->deref);
assert(load->num_components >= 2);
nir_ssa_def *ssa;
const glsl_type *type = ir->record->type;
if (field_index == type->field_index("code")) {
/* last channel holds residency code */
ssa = nir_channel(&b, load, load->num_components - 1);
} else {
assert(field_index == type->field_index("texel"));
unsigned mask = BITFIELD_MASK(load->num_components - 1);
ssa = nir_channels(&b, load, mask);
}
/* still need to create a deref for return */
nir_variable *tmp =
nir_local_variable_create(this->impl, ir->type, "deref_tmp");
this->deref = nir_build_deref_var(&b, tmp);
nir_store_deref(&b, this->deref, ssa, ~0);
} else
this->deref = nir_build_deref_struct(&b, this->deref, field_index);
}