nir: convert lower_samplers_as_deref to deref instructions
This also removes the legacy version of lower_samplers. Signed-off-by: Rob Clark <robdclark@gmail.com> Acked-by: Rob Clark <robdclark@gmail.com> Acked-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl> Acked-by: Dave Airlie <airlied@redhat.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
This commit is contained in:

committed by
Jason Ekstrand

parent
0bc15340be
commit
a20929fed2
@@ -57,6 +57,7 @@
|
|||||||
|
|
||||||
#include "compiler/nir/nir.h"
|
#include "compiler/nir/nir.h"
|
||||||
#include "compiler/nir/nir_builder.h"
|
#include "compiler/nir/nir_builder.h"
|
||||||
|
#include "compiler/nir/nir_deref.h"
|
||||||
#include "gl_nir.h"
|
#include "gl_nir.h"
|
||||||
#include "ir_uniform.h"
|
#include "ir_uniform.h"
|
||||||
|
|
||||||
@@ -69,37 +70,48 @@ struct lower_samplers_as_deref_state {
|
|||||||
struct hash_table *remap_table;
|
struct hash_table *remap_table;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Prepare for removing struct derefs. This pre-pass generates the name
|
||||||
|
* of the lowered deref, and calculates the lowered type and location.
|
||||||
|
* After that, once looking up (or creating if needed) the lowered var,
|
||||||
|
* constructing the new chain of deref instructions is a simple loop
|
||||||
|
* that skips the struct deref's
|
||||||
|
*
|
||||||
|
* path: appended to as we descend down the chain of deref instrs
|
||||||
|
* and remove struct derefs
|
||||||
|
* location: increased as we descend down and remove struct derefs
|
||||||
|
* type: updated as we recurse back up the chain of deref instrs
|
||||||
|
* with the resulting type after removing struct derefs
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
remove_struct_derefs(nir_deref *tail,
|
remove_struct_derefs_prep(nir_deref_instr **p, char **name,
|
||||||
struct lower_samplers_as_deref_state *state,
|
unsigned *location, const struct glsl_type **type)
|
||||||
nir_builder *b, char **path, unsigned *location)
|
|
||||||
{
|
{
|
||||||
if (!tail->child)
|
nir_deref_instr *cur = p[0], *next = p[1];
|
||||||
|
|
||||||
|
if (!next) {
|
||||||
|
*type = cur->type;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (tail->child->deref_type) {
|
switch (next->deref_type) {
|
||||||
case nir_deref_type_array: {
|
case nir_deref_type_array: {
|
||||||
unsigned length = glsl_get_length(tail->type);
|
unsigned length = glsl_get_length(cur->type);
|
||||||
|
|
||||||
remove_struct_derefs(tail->child, state, b, path, location);
|
remove_struct_derefs_prep(&p[1], name, location, type);
|
||||||
|
|
||||||
tail->type = glsl_get_array_instance(tail->child->type, length);
|
*type = glsl_get_array_instance(*type, length);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case nir_deref_type_struct: {
|
case nir_deref_type_struct: {
|
||||||
nir_deref_struct *deref_struct = nir_deref_as_struct(tail->child);
|
*location += glsl_get_record_location_offset(cur->type, next->strct.index);
|
||||||
|
ralloc_asprintf_append(name, ".%s",
|
||||||
|
glsl_get_struct_elem_name(cur->type, next->strct.index));
|
||||||
|
|
||||||
*location += glsl_get_record_location_offset(tail->type, deref_struct->index);
|
remove_struct_derefs_prep(&p[1], name, location, type);
|
||||||
ralloc_asprintf_append(path, ".%s",
|
|
||||||
glsl_get_struct_elem_name(tail->type, deref_struct->index));
|
|
||||||
|
|
||||||
remove_struct_derefs(tail->child, state, b, path, location);
|
/* skip over the struct type: */
|
||||||
|
*type = next->type;
|
||||||
/* Drop the struct deref and re-parent. */
|
|
||||||
ralloc_steal(tail, tail->child->child);
|
|
||||||
tail->type = tail->child->type;
|
|
||||||
tail->child = tail->child->child;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,71 +121,106 @@ remove_struct_derefs(nir_deref *tail,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static nir_deref_instr *
|
||||||
lower_deref(nir_deref_var *deref,
|
lower_deref(nir_builder *b, struct lower_samplers_as_deref_state *state,
|
||||||
struct lower_samplers_as_deref_state *state,
|
nir_deref_instr *deref)
|
||||||
nir_builder *b)
|
|
||||||
{
|
{
|
||||||
nir_variable *var = deref->var;
|
nir_variable *var = nir_deref_instr_get_variable(deref);
|
||||||
gl_shader_stage stage = state->shader->info.stage;
|
gl_shader_stage stage = state->shader->info.stage;
|
||||||
|
|
||||||
|
if (var->data.bindless || var->data.mode != nir_var_uniform)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
nir_deref_path path;
|
||||||
|
nir_deref_path_init(&path, deref, state->remap_table);
|
||||||
|
assert(path.path[0]->deref_type == nir_deref_type_var);
|
||||||
|
|
||||||
|
char *name = ralloc_asprintf(state->remap_table, "lower@%s", var->name);
|
||||||
unsigned location = var->data.location;
|
unsigned location = var->data.location;
|
||||||
|
const struct glsl_type *type = NULL;
|
||||||
unsigned binding;
|
unsigned binding;
|
||||||
const struct glsl_type *orig_type = deref->deref.type;
|
|
||||||
char *path;
|
|
||||||
|
|
||||||
assert(var->data.mode == nir_var_uniform);
|
/*
|
||||||
|
* We end up needing to do this in two passes, in order to generate
|
||||||
|
* the name of the lowered var (and detecting whether there even are
|
||||||
|
* any struct deref's), and then the second pass to construct the
|
||||||
|
* actual deref instructions after looking up / generating a new
|
||||||
|
* nir_variable (since we need to construct the deref_var first)
|
||||||
|
*/
|
||||||
|
|
||||||
path = ralloc_asprintf(state->remap_table, "lower@%s", var->name);
|
remove_struct_derefs_prep(path.path, &name, &location, &type);
|
||||||
remove_struct_derefs(&deref->deref, state, b, &path, &location);
|
|
||||||
|
|
||||||
assert(location < state->shader_program->data->NumUniformStorage &&
|
assert(location < state->shader_program->data->NumUniformStorage &&
|
||||||
state->shader_program->data->UniformStorage[location].opaque[stage].active);
|
state->shader_program->data->UniformStorage[location].opaque[stage].active);
|
||||||
|
|
||||||
binding = state->shader_program->data->UniformStorage[location].opaque[stage].index;
|
binding = state->shader_program->data->UniformStorage[location].opaque[stage].index;
|
||||||
|
|
||||||
if (orig_type == deref->deref.type) {
|
if (var->type == type) {
|
||||||
/* Fast path: We did not encounter any struct derefs. */
|
/* Fast path: We did not encounter any struct derefs. */
|
||||||
var->data.binding = binding;
|
var->data.binding = binding;
|
||||||
return;
|
return deref;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t hash = _mesa_key_hash_string(path);
|
uint32_t hash = _mesa_key_hash_string(name);
|
||||||
struct hash_entry *h =
|
struct hash_entry *h =
|
||||||
_mesa_hash_table_search_pre_hashed(state->remap_table, hash, path);
|
_mesa_hash_table_search_pre_hashed(state->remap_table, hash, name);
|
||||||
|
|
||||||
if (h) {
|
if (h) {
|
||||||
var = (nir_variable *)h->data;
|
var = (nir_variable *)h->data;
|
||||||
} else {
|
} else {
|
||||||
var = nir_variable_create(state->shader, nir_var_uniform, deref->deref.type, path);
|
var = nir_variable_create(state->shader, nir_var_uniform, type, name);
|
||||||
var->data.binding = binding;
|
var->data.binding = binding;
|
||||||
_mesa_hash_table_insert_pre_hashed(state->remap_table, hash, path, var);
|
_mesa_hash_table_insert_pre_hashed(state->remap_table, hash, name, var);
|
||||||
}
|
}
|
||||||
|
|
||||||
deref->var = var;
|
/* construct a new deref based on lowered var (skipping the struct deref's
|
||||||
|
* from the original deref:
|
||||||
|
*/
|
||||||
|
nir_deref_instr *new_deref = nir_build_deref_var(b, var);
|
||||||
|
for (nir_deref_instr **p = &path.path[1]; *p; p++) {
|
||||||
|
if ((*p)->deref_type == nir_deref_type_struct)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
assert((*p)->deref_type == nir_deref_type_array);
|
||||||
|
|
||||||
|
new_deref = nir_build_deref_array(b, new_deref,
|
||||||
|
nir_ssa_for_src(b, (*p)->arr.index, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_deref;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
lower_sampler(nir_tex_instr *instr, struct lower_samplers_as_deref_state *state,
|
lower_sampler(nir_tex_instr *instr, struct lower_samplers_as_deref_state *state,
|
||||||
nir_builder *b)
|
nir_builder *b)
|
||||||
{
|
{
|
||||||
if (!instr->texture || instr->texture->var->data.bindless ||
|
int texture_idx =
|
||||||
instr->texture->var->data.mode != nir_var_uniform)
|
nir_tex_instr_src_index(instr, nir_tex_src_texture_deref);
|
||||||
|
int sampler_idx =
|
||||||
|
nir_tex_instr_src_index(instr, nir_tex_src_sampler_deref);
|
||||||
|
|
||||||
|
if (texture_idx < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* In GLSL, we only fill out the texture field. The sampler is inferred */
|
assert(texture_idx >= 0 && sampler_idx >= 0);
|
||||||
assert(instr->sampler == NULL);
|
assert(instr->src[texture_idx].src.is_ssa);
|
||||||
|
assert(instr->src[sampler_idx].src.is_ssa);
|
||||||
|
assert(instr->src[texture_idx].src.ssa == instr->src[sampler_idx].src.ssa);
|
||||||
|
|
||||||
b->cursor = nir_before_instr(&instr->instr);
|
b->cursor = nir_before_instr(&instr->instr);
|
||||||
lower_deref(instr->texture, state, b);
|
|
||||||
|
|
||||||
if (instr->op != nir_texop_txf_ms &&
|
nir_deref_instr *texture_deref =
|
||||||
instr->op != nir_texop_txf_ms_mcs &&
|
lower_deref(b, state, nir_src_as_deref(instr->src[texture_idx].src));
|
||||||
instr->op != nir_texop_samples_identical) {
|
/* don't lower bindless: */
|
||||||
nir_instr_rewrite_deref(&instr->instr, &instr->sampler,
|
if (!texture_deref)
|
||||||
nir_deref_var_clone(instr->texture, instr));
|
return false;
|
||||||
} else {
|
nir_instr_rewrite_src(&instr->instr, &instr->src[texture_idx].src,
|
||||||
assert(!instr->sampler);
|
nir_src_for_ssa(&texture_deref->dest.ssa));
|
||||||
}
|
|
||||||
|
nir_deref_instr *sampler_deref =
|
||||||
|
lower_deref(b, state, nir_src_as_deref(instr->src[sampler_idx].src));
|
||||||
|
nir_instr_rewrite_src(&instr->instr, &instr->src[sampler_idx].src,
|
||||||
|
nir_src_for_ssa(&sampler_deref->dest.ssa));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -183,24 +230,26 @@ lower_intrinsic(nir_intrinsic_instr *instr,
|
|||||||
struct lower_samplers_as_deref_state *state,
|
struct lower_samplers_as_deref_state *state,
|
||||||
nir_builder *b)
|
nir_builder *b)
|
||||||
{
|
{
|
||||||
if (instr->intrinsic == nir_intrinsic_image_var_load ||
|
if (instr->intrinsic == nir_intrinsic_image_deref_load ||
|
||||||
instr->intrinsic == nir_intrinsic_image_var_store ||
|
instr->intrinsic == nir_intrinsic_image_deref_store ||
|
||||||
instr->intrinsic == nir_intrinsic_image_var_atomic_add ||
|
instr->intrinsic == nir_intrinsic_image_deref_atomic_add ||
|
||||||
instr->intrinsic == nir_intrinsic_image_var_atomic_min ||
|
instr->intrinsic == nir_intrinsic_image_deref_atomic_min ||
|
||||||
instr->intrinsic == nir_intrinsic_image_var_atomic_max ||
|
instr->intrinsic == nir_intrinsic_image_deref_atomic_max ||
|
||||||
instr->intrinsic == nir_intrinsic_image_var_atomic_and ||
|
instr->intrinsic == nir_intrinsic_image_deref_atomic_and ||
|
||||||
instr->intrinsic == nir_intrinsic_image_var_atomic_or ||
|
instr->intrinsic == nir_intrinsic_image_deref_atomic_or ||
|
||||||
instr->intrinsic == nir_intrinsic_image_var_atomic_xor ||
|
instr->intrinsic == nir_intrinsic_image_deref_atomic_xor ||
|
||||||
instr->intrinsic == nir_intrinsic_image_var_atomic_exchange ||
|
instr->intrinsic == nir_intrinsic_image_deref_atomic_exchange ||
|
||||||
instr->intrinsic == nir_intrinsic_image_var_atomic_comp_swap ||
|
instr->intrinsic == nir_intrinsic_image_deref_atomic_comp_swap ||
|
||||||
instr->intrinsic == nir_intrinsic_image_var_size) {
|
instr->intrinsic == nir_intrinsic_image_deref_size) {
|
||||||
|
|
||||||
b->cursor = nir_before_instr(&instr->instr);
|
b->cursor = nir_before_instr(&instr->instr);
|
||||||
|
nir_deref_instr *deref =
|
||||||
if (instr->variables[0]->var->data.bindless ||
|
lower_deref(b, state, nir_src_as_deref(instr->src[0]));
|
||||||
instr->variables[0]->var->data.mode != nir_var_uniform)
|
/* don't lower bindless: */
|
||||||
|
if (!deref)
|
||||||
return false;
|
return false;
|
||||||
|
nir_instr_rewrite_src(&instr->instr, &instr->src[0],
|
||||||
lower_deref(instr->variables[0], state, b);
|
nir_src_for_ssa(&deref->dest.ssa));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,7 +282,7 @@ gl_nir_lower_samplers_as_deref(nir_shader *shader,
|
|||||||
bool progress = false;
|
bool progress = false;
|
||||||
struct lower_samplers_as_deref_state state;
|
struct lower_samplers_as_deref_state state;
|
||||||
|
|
||||||
nir_assert_lowered_derefs(shader, nir_lower_texture_derefs);
|
nir_assert_unlowered_derefs(shader, nir_lower_texture_derefs);
|
||||||
|
|
||||||
state.shader = shader;
|
state.shader = shader;
|
||||||
state.shader_program = shader_program;
|
state.shader_program = shader_program;
|
||||||
@@ -248,5 +297,8 @@ gl_nir_lower_samplers_as_deref(nir_shader *shader,
|
|||||||
/* keys are freed automatically by ralloc */
|
/* keys are freed automatically by ralloc */
|
||||||
_mesa_hash_table_destroy(state.remap_table, NULL);
|
_mesa_hash_table_destroy(state.remap_table, NULL);
|
||||||
|
|
||||||
|
if (progress)
|
||||||
|
nir_remove_dead_derefs(shader);
|
||||||
|
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
@@ -837,12 +837,12 @@ st_finalize_nir(struct st_context *st, struct gl_program *prog,
|
|||||||
NIR_PASS_V(nir, st_nir_lower_uniforms_to_ubo);
|
NIR_PASS_V(nir, st_nir_lower_uniforms_to_ubo);
|
||||||
}
|
}
|
||||||
|
|
||||||
NIR_PASS_V(nir, nir_lower_deref_instrs, (nir_lower_deref_flags)~0);
|
|
||||||
|
|
||||||
if (screen->get_param(screen, PIPE_CAP_NIR_SAMPLERS_AS_DEREF))
|
if (screen->get_param(screen, PIPE_CAP_NIR_SAMPLERS_AS_DEREF))
|
||||||
NIR_PASS_V(nir, gl_nir_lower_samplers_as_deref, shader_program);
|
NIR_PASS_V(nir, gl_nir_lower_samplers_as_deref, shader_program);
|
||||||
else
|
else
|
||||||
NIR_PASS_V(nir, gl_nir_lower_samplers_legacy, shader_program);
|
NIR_PASS_V(nir, gl_nir_lower_samplers, shader_program);
|
||||||
|
|
||||||
|
NIR_PASS_V(nir, nir_lower_deref_instrs, (nir_lower_deref_flags)~0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
Reference in New Issue
Block a user