nak: Optimize bindless to cbuf textures on Volta+

Reviewed-by: Mel Henning <drawoc@darkrefraction.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27755>
This commit is contained in:
Faith Ekstrand 2024-02-22 13:32:07 -06:00 committed by Marge Bot
parent 272e8ec461
commit c1510ad72e
3 changed files with 117 additions and 23 deletions

View file

@ -1745,6 +1745,18 @@ impl<'a> ShaderFromNir<'a> {
let flags: nak_nir_tex_flags =
unsafe { std::mem::transmute_copy(&tex.backend_flags) };
let tex_ref = match flags.ref_type() {
NAK_NIR_TEX_REF_TYPE_BOUND => {
TexRef::Bound(tex.texture_index.try_into().unwrap())
}
NAK_NIR_TEX_REF_TYPE_CBUF => TexRef::CBuf(TexCBufRef {
idx: (tex.texture_index >> 16).try_into().unwrap(),
offset: tex.texture_index as u16,
}),
NAK_NIR_TEX_REF_TYPE_BINDLESS => TexRef::Bindless,
_ => panic!("Invalid tex ref type"),
};
let mask = tex.def.components_read();
let mut mask = u8::try_from(mask).unwrap();
if flags.is_sparse() {
@ -1774,7 +1786,7 @@ impl<'a> ShaderFromNir<'a> {
assert!(fault.is_none());
b.push_op(OpTxq {
dsts: dsts,
tex: TexRef::Bindless,
tex: tex_ref,
src: src,
query: TexQuery::Dimension,
mask: mask,
@ -1784,7 +1796,7 @@ impl<'a> ShaderFromNir<'a> {
assert!(fault.is_none());
b.push_op(OpTxq {
dsts: dsts,
tex: TexRef::Bindless,
tex: tex_ref,
src: src,
query: TexQuery::TextureType,
mask: mask,
@ -1816,7 +1828,7 @@ impl<'a> ShaderFromNir<'a> {
b.push_op(OpTxd {
dsts: dsts,
fault,
tex: TexRef::Bindless,
tex: tex_ref,
srcs: srcs,
dim: dim,
offset: offset_mode == Tld4OffsetMode::AddOffI,
@ -1826,7 +1838,7 @@ impl<'a> ShaderFromNir<'a> {
assert!(offset_mode == Tld4OffsetMode::None);
b.push_op(OpTmml {
dsts: dsts,
tex: TexRef::Bindless,
tex: tex_ref,
srcs: srcs,
dim: dim,
mask: mask,
@ -1836,7 +1848,7 @@ impl<'a> ShaderFromNir<'a> {
b.push_op(OpTld {
dsts: dsts,
fault,
tex: TexRef::Bindless,
tex: tex_ref,
srcs: srcs,
dim: dim,
lod_mode: lod_mode,
@ -1848,7 +1860,7 @@ impl<'a> ShaderFromNir<'a> {
b.push_op(OpTld4 {
dsts: dsts,
fault,
tex: TexRef::Bindless,
tex: tex_ref,
srcs: srcs,
dim: dim,
comp: tex.component().try_into().unwrap(),
@ -1861,7 +1873,7 @@ impl<'a> ShaderFromNir<'a> {
b.push_op(OpTex {
dsts: dsts,
fault,
tex: TexRef::Bindless,
tex: tex_ref,
srcs: srcs,
dim: dim,
lod_mode: lod_mode,

View file

@ -9,6 +9,27 @@
#include "util/u_math.h"
static bool
tex_handle_as_cbuf(nir_def *tex_h, uint32_t *cbuf_out)
{
if (tex_h->parent_instr->type != nir_instr_type_intrinsic)
return false;
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(tex_h->parent_instr);
if (intrin->intrinsic != nir_intrinsic_load_ubo)
return false;
if (!nir_src_is_const(intrin->src[1]))
return false;
uint32_t idx = nir_src_as_uint(intrin->src[0]);
uint32_t offset = nir_src_as_uint(intrin->src[1]);
assert(idx < (1 << 5) && offset < (1 << 16));
*cbuf_out = (idx << 16) | offset;
return true;
}
static enum glsl_sampler_dim
remap_sampler_dim(enum glsl_sampler_dim dim)
{
@ -51,6 +72,12 @@ lower_tex(nir_builder *b, nir_tex_instr *tex, const struct nak_compiler *nak)
nir_iand_imm(b, samp_h, 0xfff00000));
}
enum nak_nir_tex_ref_type ref_type = NAK_NIR_TEX_REF_TYPE_BINDLESS;
if (nak->sm >= 70 && tex_handle_as_cbuf(tex_h, &tex->texture_index)) {
ref_type = NAK_NIR_TEX_REF_TYPE_CBUF;
tex_h = NULL;
}
/* Array index is treated separately, so pull it off if we have one. */
nir_def *arr_idx = NULL;
unsigned coord_components = tex->coord_components;
@ -149,7 +176,8 @@ lower_tex(nir_builder *b, nir_tex_instr *tex, const struct nak_compiler *nak)
if (nak->sm >= 50) {
if (tex->op == nir_texop_txd) {
PUSH(src0, tex_h);
if (tex_h != NULL)
PUSH(src0, tex_h);
for (uint32_t i = 0; i < coord_components; i++)
PUSH(src0, nir_channel(b, coord, i));
@ -181,7 +209,8 @@ lower_tex(nir_builder *b, nir_tex_instr *tex, const struct nak_compiler *nak)
for (uint32_t i = 0; i < coord_components; i++)
PUSH(src0, nir_channel(b, coord, i));
PUSH(src1, tex_h);
if (tex_h != NULL)
PUSH(src1, tex_h);
if (ms_idx != NULL)
PUSH(src1, ms_idx);
if (lod != NULL)
@ -199,6 +228,9 @@ lower_tex(nir_builder *b, nir_tex_instr *tex, const struct nak_compiler *nak)
unreachable("Unsupported shader model");
}
if (src1_comps == 0)
PUSH(src1, nir_imm_int(b, 0));
nir_def *vec_srcs[2] = {
nir_vec(b, src0, src0_comps),
nir_vec(b, src1, src1_comps),
@ -217,6 +249,7 @@ lower_tex(nir_builder *b, nir_tex_instr *tex, const struct nak_compiler *nak)
tex->sampler_dim = remap_sampler_dim(tex->sampler_dim);
struct nak_nir_tex_flags flags = {
.ref_type = ref_type,
.lod_mode = lod_mode,
.offset_mode = offset_mode,
.has_z_cmpr = tex->is_shadow,
@ -270,6 +303,12 @@ lower_txq(nir_builder *b, nir_tex_instr *tex, const struct nak_compiler *nak)
}
}
enum nak_nir_tex_ref_type ref_type = NAK_NIR_TEX_REF_TYPE_BINDLESS;
if (nak->sm >= 70 && tex_handle_as_cbuf(tex_h, &tex->texture_index)) {
ref_type = NAK_NIR_TEX_REF_TYPE_CBUF;
tex_h = NULL;
}
nir_def *txq_src;
nir_component_mask_t mask;
switch (tex->op) {
@ -277,17 +316,18 @@ lower_txq(nir_builder *b, nir_tex_instr *tex, const struct nak_compiler *nak)
tex->op = nir_texop_hdr_dim_nv;
if (lod == NULL)
lod = nir_imm_int(b, 0);
txq_src = nir_vec2(b, tex_h, lod);
txq_src = tex_h != NULL ? nir_vec2(b, tex_h, lod) : lod;
mask = BITSET_MASK(tex->def.num_components);
break;
case nir_texop_query_levels:
tex->op = nir_texop_hdr_dim_nv;
txq_src = nir_vec2(b, tex_h, nir_imm_int(b, 0));
lod = nir_imm_int(b, 0);
txq_src = tex_h != NULL ? nir_vec2(b, tex_h, lod) : lod;
mask = BITSET_BIT(3);
break;
case nir_texop_texture_samples:
tex->op = nir_texop_tex_type_nv;
txq_src = tex_h;
txq_src = tex_h != NULL ? tex_h : nir_imm_int(b, 0);
mask = BITSET_BIT(2);
break;
default:
@ -303,6 +343,12 @@ lower_txq(nir_builder *b, nir_tex_instr *tex, const struct nak_compiler *nak)
tex->sampler_dim = remap_sampler_dim(tex->sampler_dim);
struct nak_nir_tex_flags flags = {
.ref_type = ref_type,
};
STATIC_ASSERT(sizeof(flags) == sizeof(tex->backend_flags));
memcpy(&tex->backend_flags, &flags, sizeof(flags));
b->cursor = nir_after_instr(&tex->instr);
/* Only pick off slected components */
@ -485,31 +531,32 @@ lower_image_txq(nir_builder *b, nir_intrinsic_instr *intrin,
nir_def *img_h = intrin->src[0].ssa;
uint32_t texture_index = 0;
enum nak_nir_tex_ref_type ref_type = NAK_NIR_TEX_REF_TYPE_BINDLESS;
if (nak->sm >= 70 && tex_handle_as_cbuf(img_h, &texture_index)) {
ref_type = NAK_NIR_TEX_REF_TYPE_CBUF;
img_h = NULL;
}
nir_tex_instr *txq = nir_tex_instr_create(b->shader, 1);
txq->sampler_dim = remap_sampler_dim(nir_intrinsic_image_dim(intrin));
txq->is_array = nir_intrinsic_image_array(intrin);
txq->dest_type = nir_type_int32;
nir_def *txq_src;
nir_component_mask_t mask;
switch (intrin->intrinsic) {
case nir_intrinsic_bindless_image_size: {
nir_def *lod = intrin->src[1].ssa;
txq->op = nir_texop_hdr_dim_nv;
txq->src[0] = (nir_tex_src) {
.src_type = nir_tex_src_backend1,
.src = nir_src_for_ssa(nir_vec2(b, img_h, lod)),
};
nir_def *lod = intrin->src[1].ssa;
txq_src = img_h != NULL ? nir_vec2(b, img_h, lod) : lod;
mask = BITSET_MASK(intrin->def.num_components);
break;
}
case nir_intrinsic_bindless_image_samples:
txq->op = nir_texop_tex_type_nv;
txq->src[0] = (nir_tex_src) {
.src_type = nir_tex_src_backend1,
.src = nir_src_for_ssa(img_h),
};
txq_src = img_h != NULL ? img_h : nir_imm_int(b, 0);
mask = BITSET_BIT(2);
break;
@ -517,6 +564,18 @@ lower_image_txq(nir_builder *b, nir_intrinsic_instr *intrin,
unreachable("Invalid image query op");
}
txq->src[0] = (nir_tex_src) {
.src_type = nir_tex_src_backend1,
.src = nir_src_for_ssa(txq_src),
};
txq->texture_index = texture_index;
struct nak_nir_tex_flags flags = {
.ref_type = ref_type,
};
STATIC_ASSERT(sizeof(flags) == sizeof(txq->backend_flags));
memcpy(&txq->backend_flags, &flags, sizeof(flags));
nir_def_init(&txq->instr, &txq->def, 4, 32);
nir_builder_instr_insert(b, &txq->instr);

View file

@ -144,6 +144,23 @@ struct nak_io_addr_offset {
struct nak_io_addr_offset
nak_get_io_addr_offset(nir_def *addr, uint8_t imm_bits);
enum nak_nir_tex_ref_type {
/** Indicates that this is a bindless texture */
NAK_NIR_TEX_REF_TYPE_BINDLESS,
/** Indicates that this is a bound texture
*
* The binding index provided in texture_index.
*/
NAK_NIR_TEX_REF_TYPE_BOUND,
/** Indicates that this is a cbuf texture
*
* texture_index is (idx << 16) | offset.
*/
NAK_NIR_TEX_REF_TYPE_CBUF,
};
enum nak_nir_lod_mode {
NAK_NIR_LOD_MODE_AUTO = 0,
NAK_NIR_LOD_MODE_ZERO,
@ -159,13 +176,19 @@ enum nak_nir_offset_mode {
NAK_NIR_OFFSET_MODE_PER_PX,
};
PRAGMA_DIAGNOSTIC_PUSH
PRAGMA_DIAGNOSTIC_ERROR(-Wpadded)
struct nak_nir_tex_flags {
enum nak_nir_tex_ref_type ref_type:2;
enum nak_nir_lod_mode lod_mode:3;
enum nak_nir_offset_mode offset_mode:2;
bool has_z_cmpr:1;
bool is_sparse:1;
uint32_t pad:25;
uint32_t pad:23;
};
PRAGMA_DIAGNOSTIC_POP
static_assert(sizeof(struct nak_nir_tex_flags) == 4,
"nak_nir_tex_flags has no holes");
bool nak_nir_lower_scan_reduce(nir_shader *shader);
bool nak_nir_lower_tex(nir_shader *nir, const struct nak_compiler *nak);