+#include "iris_defines.h"
+
+static bool
+prim_is_points_or_lines(const struct pipe_draw_info *draw)
+{
+ /* We don't need to worry about adjacency - it can only be used with
+ * geometry shaders, and we don't care about this info when GS is on.
+ */
+ return draw->mode == PIPE_PRIM_POINTS ||
+ draw->mode == PIPE_PRIM_LINES ||
+ draw->mode == PIPE_PRIM_LINE_LOOP ||
+ draw->mode == PIPE_PRIM_LINE_STRIP;
+}
+
+/**
+ * Record the current primitive mode and restart information, flagging
+ * related packets as dirty if necessary.
+ *
+ * This must be called before updating compiled shaders, because the patch
+ * information informs the TCS key.
+ */
+static void
+iris_update_draw_info(struct iris_context *ice,
+ const struct pipe_draw_info *info)
+{
+ struct iris_screen *screen = (struct iris_screen *)ice->ctx.screen;
+ const struct brw_compiler *compiler = screen->compiler;
+
+ if (ice->state.prim_mode != info->mode) {
+ ice->state.prim_mode = info->mode;
+ ice->state.dirty |= IRIS_DIRTY_VF_TOPOLOGY;
+
+
+ /* For XY Clip enables */
+ bool points_or_lines = prim_is_points_or_lines(info);
+ if (points_or_lines != ice->state.prim_is_points_or_lines) {
+ ice->state.prim_is_points_or_lines = points_or_lines;
+ ice->state.dirty |= IRIS_DIRTY_CLIP;
+ }
+ }
+
+ if (info->mode == PIPE_PRIM_PATCHES &&
+ ice->state.vertices_per_patch != info->vertices_per_patch) {
+ ice->state.vertices_per_patch = info->vertices_per_patch;
+ ice->state.dirty |= IRIS_DIRTY_VF_TOPOLOGY;
+
+ /* 8_PATCH TCS needs this for key->input_vertices */
+ if (compiler->use_tcs_8_patch)
+ ice->state.dirty |= IRIS_DIRTY_UNCOMPILED_TCS;
+
+ /* Flag constants dirty for gl_PatchVerticesIn if needed. */
+ const struct shader_info *tcs_info =
+ iris_get_shader_info(ice, MESA_SHADER_TESS_CTRL);
+ if (tcs_info &&
+ tcs_info->system_values_read & (1ull << SYSTEM_VALUE_VERTICES_IN)) {
+ ice->state.dirty |= IRIS_DIRTY_CONSTANTS_TCS;
+ ice->state.shaders[MESA_SHADER_TESS_CTRL].sysvals_need_upload = true;
+ }
+ }
+
+ if (ice->state.primitive_restart != info->primitive_restart ||
+ ice->state.cut_index != info->restart_index) {
+ ice->state.dirty |= IRIS_DIRTY_VF;
+ ice->state.primitive_restart = info->primitive_restart;
+ ice->state.cut_index = info->restart_index;
+ }
+}
+
+/**
+ * Update shader draw parameters, flagging VF packets as dirty if necessary.
+ */
+static void
+iris_update_draw_parameters(struct iris_context *ice,
+ const struct pipe_draw_info *info)
+{
+ bool changed = false;
+
+ if (ice->state.vs_uses_draw_params) {
+ struct iris_state_ref *draw_params = &ice->draw.draw_params;
+
+ if (info->indirect) {
+ pipe_resource_reference(&draw_params->res, info->indirect->buffer);
+ draw_params->offset =
+ info->indirect->offset + (info->index_size ? 12 : 8);
+
+ changed = true;
+ ice->draw.params_valid = false;
+ } else {
+ int firstvertex = info->index_size ? info->index_bias : info->start;
+
+ if (!ice->draw.params_valid ||
+ ice->draw.params.firstvertex != firstvertex ||
+ ice->draw.params.baseinstance != info->start_instance) {
+
+ changed = true;
+ ice->draw.params.firstvertex = firstvertex;
+ ice->draw.params.baseinstance = info->start_instance;
+ ice->draw.params_valid = true;
+
+ u_upload_data(ice->ctx.stream_uploader, 0,
+ sizeof(ice->draw.params), 4, &ice->draw.params,
+ &draw_params->offset, &draw_params->res);
+ }
+ }
+ }
+
+ if (ice->state.vs_uses_derived_draw_params) {
+ struct iris_state_ref *derived_params = &ice->draw.derived_draw_params;
+ int is_indexed_draw = info->index_size ? -1 : 0;
+
+ if (ice->draw.derived_params.drawid != info->drawid ||
+ ice->draw.derived_params.is_indexed_draw != is_indexed_draw) {
+
+ changed = true;
+ ice->draw.derived_params.drawid = info->drawid;
+ ice->draw.derived_params.is_indexed_draw = is_indexed_draw;
+
+ u_upload_data(ice->ctx.stream_uploader, 0,
+ sizeof(ice->draw.derived_params), 4,
+ &ice->draw.derived_params,
+ &derived_params->offset, &derived_params->res);
+ }
+ }
+
+ if (changed) {
+ ice->state.dirty |= IRIS_DIRTY_VERTEX_BUFFERS |
+ IRIS_DIRTY_VERTEX_ELEMENTS |
+ IRIS_DIRTY_VF_SGVS;
+ }
+}
+
+static void
+iris_indirect_draw_vbo(struct iris_context *ice,
+ const struct pipe_draw_info *dinfo)
+{
+ struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];
+ struct pipe_draw_info info = *dinfo;
+
+ if (info.indirect->indirect_draw_count &&
+ ice->state.predicate == IRIS_PREDICATE_STATE_USE_BIT) {
+ /* Upload MI_PREDICATE_RESULT to GPR15.*/
+ batch->screen->vtbl.load_register_reg64(batch, CS_GPR(15), MI_PREDICATE_RESULT);
+ }
+
+ uint64_t orig_dirty = ice->state.dirty;
+
+ for (int i = 0; i < info.indirect->draw_count; i++) {
+ info.drawid = i;
+
+ iris_batch_maybe_flush(batch, 1500);
+
+ iris_update_draw_parameters(ice, &info);
+
+ batch->screen->vtbl.upload_render_state(ice, batch, &info);
+
+ ice->state.dirty &= ~IRIS_ALL_DIRTY_FOR_RENDER;
+
+ info.indirect->offset += info.indirect->stride;
+ }