+
+static uint32_t
+vs_params_offset(struct tu_cmd_buffer *cmd)
+{
+ const struct tu_program_descriptor_linkage *link =
+ &cmd->state.pipeline->program.link[MESA_SHADER_VERTEX];
+ const struct ir3_const_state *const_state = &link->const_state;
+
+ if (const_state->offsets.driver_param >= link->constlen)
+ return 0;
+
+ /* this layout is required by CP_DRAW_INDIRECT_MULTI */
+ STATIC_ASSERT(IR3_DP_DRAWID == 0);
+ STATIC_ASSERT(IR3_DP_VTXID_BASE == 1);
+ STATIC_ASSERT(IR3_DP_INSTID_BASE == 2);
+
+ /* 0 means disabled for CP_DRAW_INDIRECT_MULTI */
+ assert(const_state->offsets.driver_param != 0);
+
+ return const_state->offsets.driver_param;
+}
+
+static struct tu_draw_state
+tu6_emit_vs_params(struct tu_cmd_buffer *cmd,
+ uint32_t vertex_offset,
+ uint32_t first_instance)
+{
+ uint32_t offset = vs_params_offset(cmd);
+
+ struct tu_cs cs;
+ VkResult result = tu_cs_begin_sub_stream(&cmd->sub_cs, 3 + (offset ? 8 : 0), &cs);
+ if (result != VK_SUCCESS) {
+ cmd->record_result = result;
+ return (struct tu_draw_state) {};
+ }
+
+ /* TODO: don't make a new draw state when it doesn't change */
+
+ tu_cs_emit_regs(&cs,
+ A6XX_VFD_INDEX_OFFSET(vertex_offset),
+ A6XX_VFD_INSTANCE_START_OFFSET(first_instance));
+
+ if (offset) {
+ tu_cs_emit_pkt7(&cs, CP_LOAD_STATE6_GEOM, 3 + 4);
+ tu_cs_emit(&cs, CP_LOAD_STATE6_0_DST_OFF(offset) |
+ CP_LOAD_STATE6_0_STATE_TYPE(ST6_CONSTANTS) |
+ CP_LOAD_STATE6_0_STATE_SRC(SS6_DIRECT) |
+ CP_LOAD_STATE6_0_STATE_BLOCK(SB6_VS_SHADER) |
+ CP_LOAD_STATE6_0_NUM_UNIT(1));
+ tu_cs_emit(&cs, 0);
+ tu_cs_emit(&cs, 0);
+
+ tu_cs_emit(&cs, 0);
+ tu_cs_emit(&cs, vertex_offset);
+ tu_cs_emit(&cs, first_instance);
+ tu_cs_emit(&cs, 0);
+ }
+
+ struct tu_cs_entry entry = tu_cs_end_sub_stream(&cmd->sub_cs, &cs);
+ return (struct tu_draw_state) {entry.bo->iova + entry.offset, entry.size / 4};
+}
+