turnip, ir3: Use shader for vertex input count

Maintenance9 will require us to make unbound vertex inputs (that is,
attributes in the VS without a corresponding binding at the same
location) be defined. In order for this to work, VFD_FETCH_INSTR_INSTR
must be defined for all attributes used in the shader. Imagine we do
something like:

CmdSetVertexInputs(only 1 input at location 0)
CmdBindPipeline(VS reads only location 0)
CmdDraw()
CmdBindPipeline(VS reads locations 0 and 1)
CmdDraw()

For the first draw we only need to emit VFD_FETCH_INSTR_INSTR[0], for the
second draw we need to emit VFD_FETCH_INSTR_INSTR[1] as well in the VI
draw state. This unfortunately means we have to do draw-time validation
for vertex input state.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40552>
This commit is contained in:
Connor Abbott 2026-03-20 18:15:40 -04:00 committed by Marge Bot
parent b8a5aeee48
commit 789e765161
6 changed files with 32 additions and 17 deletions

View file

@ -5170,6 +5170,9 @@ setup_input(struct ir3_context *ctx, nir_intrinsic_instr *intr)
unsigned idx = (n * 4) + i + frac;
ctx->last_dst[i] = ctx->inputs[idx];
}
if (slot >= VERT_ATTRIB_GENERIC0)
so->attr_in = MAX2(so->attr_in, slot - VERT_ATTRIB_GENERIC0 + 1);
}
}

View file

@ -825,6 +825,11 @@ struct ir3_shader_variant {
*/
unsigned varying_in;
/* For vertex shaders, the number of generic attribute slots (i.e. 1 plus the
* max VERT_ATTRIB_GENERICn).
*/
unsigned attr_in;
/* Remapping table to map Image and SSBO to hw state: */
struct ir3_ibo_mapping image_mapping;

View file

@ -5329,7 +5329,10 @@ TU_GENX(tu_EndCommandBuffer);
static void
tu_bind_vs(struct tu_cmd_buffer *cmd, struct tu_shader *vs)
{
cmd->state.shaders[MESA_SHADER_VERTEX] = vs;
if (cmd->state.shaders[MESA_SHADER_VERTEX] != vs) {
cmd->state.shaders[MESA_SHADER_VERTEX] = vs;
cmd->state.dirty |= TU_CMD_DIRTY_VS;
}
}
static void

View file

@ -81,6 +81,7 @@ enum tu_cmd_dirty_bits
TU_CMD_DIRTY_SHADING_RATE = BIT(15),
TU_CMD_DIRTY_DISABLE_FS = BIT(16),
TU_CMD_DIRTY_TCS = BIT(17),
TU_CMD_DIRTY_VS = BIT(18),
/* all draw states were disabled and need to be re-enabled: */
TU_CMD_DIRTY_DRAW_STATE = BIT(18)

View file

@ -2451,17 +2451,18 @@ static const enum mesa_vk_dynamic_graphics_state tu_vertex_input_state[] = {
template <chip CHIP>
static unsigned
tu6_vertex_input_size(struct tu_device *dev,
const struct vk_vertex_input_state *vi)
const struct vk_vertex_input_state *vi,
unsigned attr_count)
{
return 1 + 2 * util_last_bit(vi->attributes_valid);
return 1 + 2 * attr_count;
}
template <chip CHIP>
static void
tu6_emit_vertex_input(struct tu_cs *cs,
const struct vk_vertex_input_state *vi)
const struct vk_vertex_input_state *vi,
unsigned attr_count)
{
unsigned attr_count = util_last_bit(vi->attributes_valid);
if (attr_count != 0)
tu_cs_emit_pkt4(cs, REG_A6XX_VFD_FETCH_INSTR_INSTR(0), attr_count * 2);
@ -3924,8 +3925,10 @@ tu_pipeline_builder_emit_state(struct tu_pipeline_builder *builder,
}
#define DRAW_STATE(name, id, ...) DRAW_STATE_COND(name, id, true, __VA_ARGS__)
DRAW_STATE(vertex_input, TU_DYNAMIC_STATE_VERTEX_INPUT,
builder->graphics_state.vi);
DRAW_STATE_COND(vertex_input, TU_DYNAMIC_STATE_VERTEX_INPUT,
pipeline->shaders[MESA_SHADER_VERTEX],
builder->graphics_state.vi,
pipeline->shaders[MESA_SHADER_VERTEX]->variant->attr_in);
DRAW_STATE(vertex_stride, TU_DYNAMIC_STATE_VB_STRIDE,
builder->graphics_state.vi);
/* If (a) per-view viewport is used or (b) we don't know yet, then we need
@ -4188,8 +4191,10 @@ tu_emit_draw_state(struct tu_cmd_buffer *cmd)
}
#define DRAW_STATE(name, id, ...) DRAW_STATE_COND(name, id, false, __VA_ARGS__)
DRAW_STATE(vertex_input, TU_DYNAMIC_STATE_VERTEX_INPUT,
cmd->vk.dynamic_graphics_state.vi);
DRAW_STATE_COND(vertex_input, TU_DYNAMIC_STATE_VERTEX_INPUT,
cmd->state.dirty & TU_CMD_DIRTY_VS,
cmd->vk.dynamic_graphics_state.vi,
cmd->state.shaders[MESA_SHADER_VERTEX]->variant->attr_in);
/* Vertex input stride is special because it's part of the vertex input in
* the pipeline but a separate array when it's dynamic state so we have to

View file

@ -1982,7 +1982,6 @@ tu6_emit_vfd_dest(struct tu_cs *cs,
const struct ir3_shader_variant *vs)
{
int32_t input_for_attr[MAX_VERTEX_ATTRIBS];
uint32_t attr_count = 0;
for (unsigned i = 0; i < MAX_VERTEX_ATTRIBS; i++)
input_for_attr[i] = -1;
@ -1994,13 +1993,12 @@ tu6_emit_vfd_dest(struct tu_cs *cs,
assert(vs->inputs[i].slot >= VERT_ATTRIB_GENERIC0);
unsigned loc = vs->inputs[i].slot - VERT_ATTRIB_GENERIC0;
input_for_attr[loc] = i;
attr_count = MAX2(attr_count, loc + 1);
}
tu_cs_emit_regs(cs,
A6XX_VFD_CNTL_0(
.fetch_cnt = attr_count, /* decode_cnt for binning pass ? */
.decode_cnt = attr_count));
.fetch_cnt = vs->attr_in, /* decode_cnt for binning pass ? */
.decode_cnt = vs->attr_in));
if (CHIP >= A8XX) {
const uint32_t vertexid_regid =
@ -2016,15 +2014,15 @@ tu6_emit_vfd_dest(struct tu_cs *cs,
(viewid_regid != INVALID_REG);
tu_cs_emit_regs(cs, PC_VS_INPUT_CNTL(CHIP,
.instr_cnt = attr_count,
.instr_cnt = vs->attr_in,
.sideband_cnt = sideband_count,
));
}
if (attr_count)
tu_cs_emit_pkt4(cs, REG_A6XX_VFD_DEST_CNTL_INSTR(0), attr_count);
if (vs->attr_in)
tu_cs_emit_pkt4(cs, REG_A6XX_VFD_DEST_CNTL_INSTR(0), vs->attr_in);
for (unsigned i = 0; i < attr_count; i++) {
for (unsigned i = 0; i < vs->attr_in; i++) {
if (input_for_attr[i] >= 0) {
unsigned input_idx = input_for_attr[i];
tu_cs_emit(cs, A6XX_VFD_DEST_CNTL_INSTR(0,