diff --git a/src/gallium/auxiliary/cso_cache/cso_context.c b/src/gallium/auxiliary/cso_cache/cso_context.c index 3911ee73d302eb28324091580dd947bd3bfe72c1..2fdea6cc35f405ddeb6e1fa33ec7e409ef83f02a 100644 --- a/src/gallium/auxiliary/cso_cache/cso_context.c +++ b/src/gallium/auxiliary/cso_cache/cso_context.c @@ -1727,10 +1727,14 @@ cso_draw_vbo(struct cso_context *cso, struct u_vbuf *vbuf = cso->vbuf_current; /* We can't have both indirect drawing and SO-vertex-count drawing */ - assert(info->indirect == NULL || info->count_from_stream_output == NULL); + assert(!info->indirect || + info->indirect->buffer == NULL || + info->indirect->count_from_stream_output == NULL); /* We can't have SO-vertex-count drawing with an index buffer */ - assert(info->count_from_stream_output == NULL || info->index_size == 0); + assert(info->index_size == 0 || + !info->indirect || + info->indirect->count_from_stream_output == NULL); if (vbuf) { u_vbuf_draw_vbo(vbuf, info); diff --git a/src/gallium/auxiliary/draw/draw_pt.c b/src/gallium/auxiliary/draw/draw_pt.c index 0ea1f14c1e0eef159f0ba694209c91c22cb0ffd4..a1626c7171f995291349ea29b6580655462ec6ee 100644 --- a/src/gallium/auxiliary/draw/draw_pt.c +++ b/src/gallium/auxiliary/draw/draw_pt.c @@ -445,9 +445,9 @@ resolve_draw_info(const struct pipe_draw_info *raw_info, { memcpy(info, raw_info, sizeof(struct pipe_draw_info)); - if (raw_info->count_from_stream_output) { + if (raw_info->indirect && raw_info->indirect->count_from_stream_output) { struct draw_so_target *target = - (struct draw_so_target *)info->count_from_stream_output; + (struct draw_so_target *)info->indirect->count_from_stream_output; assert(vertex_buffer != NULL); info->count = vertex_buffer->stride == 0 ? 0 : target->internal_offset / vertex_buffer->stride; @@ -455,6 +455,7 @@ resolve_draw_info(const struct pipe_draw_info *raw_info, /* Stream output draw can not be indexed */ debug_assert(!info->index_size); info->max_index = info->count - 1; + info->indirect = NULL; } } diff --git a/src/gallium/auxiliary/driver_ddebug/dd_draw.c b/src/gallium/auxiliary/driver_ddebug/dd_draw.c index b93890f4f99457660e0f898453b199f60bd6f239..e9e3b493d89178becb62ed4c9615f6f9fd2975ed 100644 --- a/src/gallium/auxiliary/driver_ddebug/dd_draw.c +++ b/src/gallium/auxiliary/driver_ddebug/dd_draw.c @@ -356,13 +356,14 @@ dd_dump_draw_vbo(struct dd_draw_state *dstate, struct pipe_draw_info *info, FILE int sh, i; DUMP(draw_info, info); - if (info->count_from_stream_output) - DUMP_M(stream_output_target, info, - count_from_stream_output); if (info->indirect) { - DUMP_M(resource, info, indirect->buffer); + if (info->indirect->buffer) + DUMP_M(resource, info, indirect->buffer); if (info->indirect->indirect_draw_count) DUMP_M(resource, info, indirect->indirect_draw_count); + if (info->indirect->count_from_stream_output) + DUMP_M(stream_output_target, info, + indirect->count_from_stream_output); } fprintf(f, "\n"); @@ -705,7 +706,7 @@ dd_unreference_copy_of_call(struct dd_call *dst) case CALL_FLUSH: break; case CALL_DRAW_VBO: - pipe_so_target_reference(&dst->info.draw_vbo.draw.count_from_stream_output, NULL); + pipe_so_target_reference(&dst->info.draw_vbo.indirect.count_from_stream_output, NULL); pipe_resource_reference(&dst->info.draw_vbo.indirect.buffer, NULL); pipe_resource_reference(&dst->info.draw_vbo.indirect.indirect_draw_count, NULL); if (dst->info.draw_vbo.draw.index_size && @@ -1305,9 +1306,6 @@ dd_context_draw_vbo(struct pipe_context *_pipe, record->call.type = CALL_DRAW_VBO; record->call.info.draw_vbo.draw = *info; - record->call.info.draw_vbo.draw.count_from_stream_output = NULL; - pipe_so_target_reference(&record->call.info.draw_vbo.draw.count_from_stream_output, - info->count_from_stream_output); if (info->index_size && !info->has_user_indices) { record->call.info.draw_vbo.draw.index.resource = NULL; pipe_resource_reference(&record->call.info.draw_vbo.draw.index.resource, @@ -1324,6 +1322,9 @@ dd_context_draw_vbo(struct pipe_context *_pipe, record->call.info.draw_vbo.indirect.indirect_draw_count = NULL; pipe_resource_reference(&record->call.info.draw_vbo.indirect.indirect_draw_count, info->indirect->indirect_draw_count); + record->call.info.draw_vbo.indirect.count_from_stream_output = NULL; + pipe_so_target_reference(&record->call.info.draw_vbo.indirect.count_from_stream_output, + info->indirect->count_from_stream_output); } else { memset(&record->call.info.draw_vbo.indirect, 0, sizeof(*info->indirect)); } diff --git a/src/gallium/auxiliary/driver_trace/tr_dump_state.c b/src/gallium/auxiliary/driver_trace/tr_dump_state.c index 49d2109101a11274670601d81093042c283397b4..c63c373f9235552ef33bcd487e5c6a52bfee53fe 100644 --- a/src/gallium/auxiliary/driver_trace/tr_dump_state.c +++ b/src/gallium/auxiliary/driver_trace/tr_dump_state.c @@ -793,7 +793,6 @@ void trace_dump_draw_info(const struct pipe_draw_info *state) trace_dump_member(uint, state, restart_index); trace_dump_member(ptr, state, index.resource); - trace_dump_member(ptr, state, count_from_stream_output); if (!state->indirect) { trace_dump_member(ptr, state, indirect); @@ -804,6 +803,7 @@ void trace_dump_draw_info(const struct pipe_draw_info *state) trace_dump_member(uint, state, indirect->indirect_draw_count_offset); trace_dump_member(ptr, state, indirect->buffer); trace_dump_member(ptr, state, indirect->indirect_draw_count); + trace_dump_member(ptr, state, indirect->count_from_stream_output); } trace_dump_struct_end(); diff --git a/src/gallium/auxiliary/util/u_draw.c b/src/gallium/auxiliary/util/u_draw.c index 90d01297c490cc58123283c7b36177e5a3babb21..a6835204c72aee819d9d185ee4f7ef747c997db0 100644 --- a/src/gallium/auxiliary/util/u_draw.c +++ b/src/gallium/auxiliary/util/u_draw.c @@ -139,7 +139,7 @@ util_draw_indirect(struct pipe_context *pipe, unsigned num_params = info_in->index_size ? 5 : 4; assert(info_in->indirect); - assert(!info_in->count_from_stream_output); + assert(!info_in->indirect->count_from_stream_output); memcpy(&info, info_in, sizeof(info)); diff --git a/src/gallium/auxiliary/util/u_dump_state.c b/src/gallium/auxiliary/util/u_dump_state.c index f57a5923ad0a1084267378ff515f79aef24d42c0..3cbd779bfd14734a86b4d28d73b9aeb9a6120da2 100644 --- a/src/gallium/auxiliary/util/u_dump_state.c +++ b/src/gallium/auxiliary/util/u_dump_state.c @@ -941,7 +941,6 @@ util_dump_draw_info(FILE *stream, const struct pipe_draw_info *state) else util_dump_member(stream, ptr, state, index.resource); } - util_dump_member(stream, ptr, state, count_from_stream_output); if (!state->indirect) { util_dump_member(stream, ptr, state, indirect); @@ -952,6 +951,7 @@ util_dump_draw_info(FILE *stream, const struct pipe_draw_info *state) util_dump_member(stream, uint, state, indirect->indirect_draw_count_offset); util_dump_member(stream, ptr, state, indirect->buffer); util_dump_member(stream, ptr, state, indirect->indirect_draw_count); + util_dump_member(stream, ptr, state, indirect->count_from_stream_output); } util_dump_struct_end(stream); diff --git a/src/gallium/auxiliary/util/u_prim_restart.c b/src/gallium/auxiliary/util/u_prim_restart.c index eef2b4c622cb00d1c82d3878c0e1fe03bb998e8d..f7b34f9ebc8ddcc60152b7434a18e9334d6422c7 100644 --- a/src/gallium/auxiliary/util/u_prim_restart.c +++ b/src/gallium/auxiliary/util/u_prim_restart.c @@ -114,7 +114,7 @@ util_translate_prim_restart_ib(struct pipe_context *context, dst_index_size = MAX2(2, info->index_size); assert(dst_index_size == 2 || dst_index_size == 4); - if (info->indirect) { + if (info->indirect && info->indirect->buffer) { indirect = read_indirect_elements(context, info->indirect); count = indirect.count; start = indirect.firstIndex; @@ -235,7 +235,7 @@ util_draw_vbo_without_prim_restart(struct pipe_context *context, assert(info->index_size); assert(info->primitive_restart); - if (info->indirect) { + if (info->indirect && info->indirect->buffer) { indirect = read_indirect_elements(context, info->indirect); info_count = indirect.count; info_start = indirect.firstIndex; diff --git a/src/gallium/auxiliary/util/u_threaded_context.c b/src/gallium/auxiliary/util/u_threaded_context.c index 5da9a177fa8c1c9a44d14c3325b13c5f39d485a0..f66280da6f62f429aa0e17669aceade35e8ae49f 100644 --- a/src/gallium/auxiliary/util/u_threaded_context.c +++ b/src/gallium/auxiliary/util/u_threaded_context.c @@ -126,7 +126,6 @@ tc_batch_execute(void *job, UNUSED int thread_index) if (next != last && next->call_id == TC_CALL_draw_vbo && first_info->draw.drawid == 0 && !first_info->draw.indirect && - !first_info->draw.count_from_stream_output && is_next_call_a_mergeable_draw(first_info, next, &next_info)) { /* Merge up to 256 draw calls. */ struct pipe_draw_start_count multi[256]; @@ -2199,12 +2198,12 @@ tc_call_draw_vbo(struct pipe_context *pipe, union tc_payload *payload) struct tc_full_draw_info *info = (struct tc_full_draw_info*)payload; pipe->draw_vbo(pipe, &info->draw); - pipe_so_target_reference(&info->draw.count_from_stream_output, NULL); if (info->draw.index_size) pipe_resource_reference(&info->draw.index.resource, NULL); if (info->draw.indirect) { pipe_resource_reference(&info->indirect.buffer, NULL); pipe_resource_reference(&info->indirect.indirect_draw_count, NULL); + pipe_so_target_reference(&info->indirect.count_from_stream_output, NULL); } } @@ -2243,9 +2242,6 @@ tc_draw_vbo(struct pipe_context *_pipe, const struct pipe_draw_info *info) return; struct tc_full_draw_info *p = tc_add_draw_vbo(_pipe, false); - p->draw.count_from_stream_output = NULL; - pipe_so_target_reference(&p->draw.count_from_stream_output, - info->count_from_stream_output); memcpy(&p->draw, info, sizeof(*info)); p->draw.has_user_indices = false; p->draw.index.resource = buffer; @@ -2253,9 +2249,6 @@ tc_draw_vbo(struct pipe_context *_pipe, const struct pipe_draw_info *info) } else { /* Non-indexed call or indexed with a real index buffer. */ struct tc_full_draw_info *p = tc_add_draw_vbo(_pipe, indirect != NULL); - p->draw.count_from_stream_output = NULL; - pipe_so_target_reference(&p->draw.count_from_stream_output, - info->count_from_stream_output); if (index_size) { tc_set_resource_reference(&p->draw.index.resource, info->index.resource); @@ -2266,6 +2259,9 @@ tc_draw_vbo(struct pipe_context *_pipe, const struct pipe_draw_info *info) tc_set_resource_reference(&p->draw.indirect->buffer, indirect->buffer); tc_set_resource_reference(&p->indirect.indirect_draw_count, indirect->indirect_draw_count); + p->indirect.count_from_stream_output = NULL; + pipe_so_target_reference(&p->indirect.count_from_stream_output, + indirect->count_from_stream_output); memcpy(&p->indirect, indirect, sizeof(*indirect)); p->draw.indirect = &p->indirect; } diff --git a/src/gallium/auxiliary/util/u_vbuf.c b/src/gallium/auxiliary/util/u_vbuf.c index 511a97dd806a9f7bbc529520105e960416c324f0..19898dc7dc5b18d874c68e391e347b7f2f7da27c 100644 --- a/src/gallium/auxiliary/util/u_vbuf.c +++ b/src/gallium/auxiliary/util/u_vbuf.c @@ -1306,7 +1306,7 @@ void u_vbuf_draw_vbo(struct u_vbuf *mgr, const struct pipe_draw_info *info) new_info = *info; /* Handle indirect (multi)draws. */ - if (new_info.indirect) { + if (new_info.indirect && new_info.indirect->buffer) { const struct pipe_draw_indirect_info *indirect = new_info.indirect; unsigned draw_count = 0; diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.c b/src/gallium/drivers/etnaviv/etnaviv_context.c index 9c334a450c67fa4c63eb26fb9f2066917386a6ba..40d9656affdb4b78c6191f0f625e831eaa09a01b 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_context.c +++ b/src/gallium/drivers/etnaviv/etnaviv_context.c @@ -231,7 +231,7 @@ etna_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) uint32_t draw_mode; unsigned i; - if (!info->count_from_stream_output && !info->indirect && + if (!info->indirect && !info->primitive_restart && !u_trim_pipe_prim(info->mode, (unsigned*)&info->count)) return; diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_draw.h b/src/gallium/drivers/freedreno/a4xx/fd4_draw.h index 57aabf529d124f195c98c83e7527369dae30e1f4..bf3a6346aa6d218e4978bd5a1f080e69460ee152 100644 --- a/src/gallium/drivers/freedreno/a4xx/fd4_draw.h +++ b/src/gallium/drivers/freedreno/a4xx/fd4_draw.h @@ -97,7 +97,7 @@ fd4_draw_emit(struct fd_batch *batch, struct fd_ringbuffer *ring, enum pc_di_src_sel src_sel; uint32_t idx_size, idx_offset; - if (info->indirect) { + if (info->indirect && info->indirect->buffer) { struct fd_resource *ind = fd_resource(info->indirect->buffer); emit_marker(ring, 7); diff --git a/src/gallium/drivers/freedreno/a5xx/fd5_draw.h b/src/gallium/drivers/freedreno/a5xx/fd5_draw.h index 2dfd95304af50c345fab6a19a77ce1f1ec22a220..71ede21a96fcb8dcdf35ea625720a95540f86365 100644 --- a/src/gallium/drivers/freedreno/a5xx/fd5_draw.h +++ b/src/gallium/drivers/freedreno/a5xx/fd5_draw.h @@ -91,7 +91,7 @@ fd5_draw_emit(struct fd_batch *batch, struct fd_ringbuffer *ring, enum pc_di_src_sel src_sel; uint32_t max_indices, idx_offset; - if (info->indirect) { + if (info->indirect && info->indirect->buffer) { struct fd_resource *ind = fd_resource(info->indirect->buffer); emit_marker5(ring, 7); diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_draw.c b/src/gallium/drivers/freedreno/a6xx/fd6_draw.c index c68ae9445cc76b683e7a66b791564e072a4ae5d3..3f23289baa346f1de1c6defa2224a1a5b6b906ce 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_draw.c +++ b/src/gallium/drivers/freedreno/a6xx/fd6_draw.c @@ -195,7 +195,7 @@ fd6_draw_vbo(struct fd_context *ctx, const struct pipe_draw_info *info, if (emit.key.gs) emit.key.key.has_gs = true; - if (!(emit.key.hs || emit.key.ds || emit.key.gs || info->indirect)) + if (!(emit.key.hs || emit.key.ds || emit.key.gs || (info->indirect && info->indirect->buffer))) fd6_vsc_update_sizes(ctx->batch, info); fixup_shader_state(ctx, &emit.key.key); @@ -315,7 +315,7 @@ fd6_draw_vbo(struct fd_context *ctx, const struct pipe_draw_info *info, */ emit_marker6(ring, 7); - if (info->indirect) { + if (info->indirect && info->indirect->buffer) { draw_emit_indirect(ring, &draw0, info, index_offset); } else { draw_emit(ring, &draw0, info, index_offset); diff --git a/src/gallium/drivers/freedreno/freedreno_draw.c b/src/gallium/drivers/freedreno/freedreno_draw.c index 9437c7d1eae58f7e62148651d27af18a6e095281..9e432b0e173e8968618d700ecec85ec49111d88b 100644 --- a/src/gallium/drivers/freedreno/freedreno_draw.c +++ b/src/gallium/drivers/freedreno/freedreno_draw.c @@ -175,7 +175,7 @@ batch_draw_tracking(struct fd_batch *batch, const struct pipe_draw_info *info) resource_read(batch, info->index.resource); /* Mark indirect draw buffer as being read */ - if (info->indirect) + if (info->indirect && info->indirect->buffer) resource_read(batch, info->indirect->buffer); /* Mark textures as being read */ @@ -218,13 +218,13 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) * to be able to emulate it, to determine if game is feeding us * bogus data: */ - if (info->indirect && (fd_mesa_debug & FD_DBG_NOINDR)) { + if (info->indirect && info->indirect->buffer && (fd_mesa_debug & FD_DBG_NOINDR)) { util_draw_indirect(pctx, info); return; } if (info->mode != PIPE_PRIM_MAX && - !info->count_from_stream_output && !info->indirect && + !info->indirect && !info->primitive_restart && !u_trim_pipe_prim(info->mode, (unsigned*)&info->count)) return; diff --git a/src/gallium/drivers/iris/iris_draw.c b/src/gallium/drivers/iris/iris_draw.c index fc545eb7d36d79237b78f04b4d6bdc253bfa335c..171ce4f5a6e98ecaf18677a0cee43f9c452b197a 100644 --- a/src/gallium/drivers/iris/iris_draw.c +++ b/src/gallium/drivers/iris/iris_draw.c @@ -118,7 +118,7 @@ iris_update_draw_parameters(struct iris_context *ice, if (ice->state.vs_uses_draw_params) { struct iris_state_ref *draw_params = &ice->draw.draw_params; - if (info->indirect) { + if (info->indirect && info->indirect->buffer) { pipe_resource_reference(&draw_params->res, info->indirect->buffer); draw_params->offset = info->indirect->offset + (info->index_size ? 12 : 8); @@ -192,7 +192,7 @@ iris_indirect_draw_vbo(struct iris_context *ice, iris_update_draw_parameters(ice, &info); - batch->screen->vtbl.upload_render_state(ice, batch, &info); + batch->screen->vtbl.upload_render_state(ice, batch, &info, info.indirect); ice->state.dirty &= ~IRIS_ALL_DIRTY_FOR_RENDER; ice->state.stage_dirty &= ~IRIS_ALL_STAGE_DIRTY_FOR_RENDER; @@ -221,7 +221,7 @@ iris_simple_draw_vbo(struct iris_context *ice, iris_update_draw_parameters(ice, draw); - batch->screen->vtbl.upload_render_state(ice, batch, draw); + batch->screen->vtbl.upload_render_state(ice, batch, draw, draw->indirect); } /** @@ -234,6 +234,7 @@ iris_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info) struct iris_screen *screen = (struct iris_screen*)ice->ctx.screen; const struct gen_device_info *devinfo = &screen->devinfo; struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER]; + struct pipe_draw_indirect_info *indirect = info->indirect; if (ice->state.predicate == IRIS_PREDICATE_STATE_DONT_RENDER) return; @@ -269,7 +270,7 @@ iris_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info) iris_handle_always_flush_cache(batch); - if (info->indirect) + if (indirect && indirect->buffer) iris_indirect_draw_vbo(ice, info); else iris_simple_draw_vbo(ice, info); diff --git a/src/gallium/drivers/iris/iris_screen.h b/src/gallium/drivers/iris/iris_screen.h index 1a03a3f46df5ca615260f4b744a78df1f37a2dd6..420c347a7ce23465e5fc40abc1f94c24a497a4b8 100644 --- a/src/gallium/drivers/iris/iris_screen.h +++ b/src/gallium/drivers/iris/iris_screen.h @@ -60,7 +60,8 @@ struct iris_vtable { void (*init_compute_context)(struct iris_batch *batch); void (*upload_render_state)(struct iris_context *ice, struct iris_batch *batch, - const struct pipe_draw_info *draw); + const struct pipe_draw_info *draw, + const struct pipe_draw_indirect_info *indirect); void (*update_surface_base_address)(struct iris_batch *batch, struct iris_binder *binder); void (*upload_compute_state)(struct iris_context *ice, diff --git a/src/gallium/drivers/iris/iris_state.c b/src/gallium/drivers/iris/iris_state.c index 59a63f7bbabe72b97170248468449203cf3bb822..cc41a07f6d477946f50d9af7320848d82e2f3c22 100644 --- a/src/gallium/drivers/iris/iris_state.c +++ b/src/gallium/drivers/iris/iris_state.c @@ -6417,7 +6417,8 @@ iris_upload_dirty_render_state(struct iris_context *ice, static void iris_upload_render_state(struct iris_context *ice, struct iris_batch *batch, - const struct pipe_draw_info *draw) + const struct pipe_draw_info *draw, + const struct pipe_draw_indirect_info *indirect) { bool use_predicate = ice->state.predicate == IRIS_PREDICATE_STATE_USE_BIT; @@ -6492,14 +6493,14 @@ iris_upload_render_state(struct iris_context *ice, #define _3DPRIM_START_INSTANCE 0x243C #define _3DPRIM_BASE_VERTEX 0x2440 - if (draw->indirect) { - if (draw->indirect->indirect_draw_count) { + if (indirect && !indirect->count_from_stream_output) { + if (indirect->indirect_draw_count) { use_predicate = true; struct iris_bo *draw_count_bo = - iris_resource_bo(draw->indirect->indirect_draw_count); + iris_resource_bo(indirect->indirect_draw_count); unsigned draw_count_offset = - draw->indirect->indirect_draw_count_offset; + indirect->indirect_draw_count_offset; iris_emit_pipe_control_flush(batch, "ensure indirect draw buffer is flushed", @@ -6551,43 +6552,43 @@ iris_upload_render_state(struct iris_context *ice, iris_batch_emit(batch, &mi_predicate, sizeof(uint32_t)); } } - struct iris_bo *bo = iris_resource_bo(draw->indirect->buffer); + struct iris_bo *bo = iris_resource_bo(indirect->buffer); assert(bo); iris_emit_cmd(batch, GENX(MI_LOAD_REGISTER_MEM), lrm) { lrm.RegisterAddress = _3DPRIM_VERTEX_COUNT; - lrm.MemoryAddress = ro_bo(bo, draw->indirect->offset + 0); + lrm.MemoryAddress = ro_bo(bo, indirect->offset + 0); } iris_emit_cmd(batch, GENX(MI_LOAD_REGISTER_MEM), lrm) { lrm.RegisterAddress = _3DPRIM_INSTANCE_COUNT; - lrm.MemoryAddress = ro_bo(bo, draw->indirect->offset + 4); + lrm.MemoryAddress = ro_bo(bo, indirect->offset + 4); } iris_emit_cmd(batch, GENX(MI_LOAD_REGISTER_MEM), lrm) { lrm.RegisterAddress = _3DPRIM_START_VERTEX; - lrm.MemoryAddress = ro_bo(bo, draw->indirect->offset + 8); + lrm.MemoryAddress = ro_bo(bo, indirect->offset + 8); } if (draw->index_size) { iris_emit_cmd(batch, GENX(MI_LOAD_REGISTER_MEM), lrm) { lrm.RegisterAddress = _3DPRIM_BASE_VERTEX; - lrm.MemoryAddress = ro_bo(bo, draw->indirect->offset + 12); + lrm.MemoryAddress = ro_bo(bo, indirect->offset + 12); } iris_emit_cmd(batch, GENX(MI_LOAD_REGISTER_MEM), lrm) { lrm.RegisterAddress = _3DPRIM_START_INSTANCE; - lrm.MemoryAddress = ro_bo(bo, draw->indirect->offset + 16); + lrm.MemoryAddress = ro_bo(bo, indirect->offset + 16); } } else { iris_emit_cmd(batch, GENX(MI_LOAD_REGISTER_MEM), lrm) { lrm.RegisterAddress = _3DPRIM_START_INSTANCE; - lrm.MemoryAddress = ro_bo(bo, draw->indirect->offset + 12); + lrm.MemoryAddress = ro_bo(bo, indirect->offset + 12); } iris_emit_cmd(batch, GENX(MI_LOAD_REGISTER_IMM), lri) { lri.RegisterOffset = _3DPRIM_BASE_VERTEX; lri.DataDWord = 0; } } - } else if (draw->count_from_stream_output) { + } else if (indirect && indirect->count_from_stream_output) { struct iris_stream_output_target *so = - (void *) draw->count_from_stream_output; + (void *) indirect->count_from_stream_output; /* XXX: Replace with actual cache tracking */ iris_emit_pipe_control_flush(batch, @@ -6615,7 +6616,7 @@ iris_upload_render_state(struct iris_context *ice, prim.VertexAccessType = draw->index_size > 0 ? RANDOM : SEQUENTIAL; prim.PredicateEnable = use_predicate; - if (draw->indirect || draw->count_from_stream_output) { + if (indirect) { prim.IndirectParameterEnable = true; } else { prim.StartInstanceLocation = draw->start_instance; diff --git a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c index d9700cfd6d78a580e381cd3c65f38412d0306fc3..4ee88c888e8deee802547dad25a7d25d424ba17f 100644 --- a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c +++ b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c @@ -61,7 +61,7 @@ llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) if (!llvmpipe_check_render_cond(lp)) return; - if (info->indirect) { + if (info->indirect && info->indirect->buffer) { util_draw_indirect(pipe, info); return; } diff --git a/src/gallium/drivers/nouveau/nv50/nv50_push.c b/src/gallium/drivers/nouveau/nv50/nv50_push.c index d835e9d696a1a8db3afa4f2c920b027f6e396dd1..d10399530c9afa87bea1e04847689431552e51c3 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_push.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_push.c @@ -292,10 +292,10 @@ nv50_push_vbo(struct nv50_context *nv50, const struct pipe_draw_info *info) ctx.primitive_restart = info->primitive_restart; ctx.restart_index = info->restart_index; } else { - if (unlikely(info->count_from_stream_output)) { + if (unlikely(info->indirect && info->indirect->count_from_stream_output)) { struct pipe_context *pipe = &nv50->base.pipe; struct nv50_so_target *targ; - targ = nv50_so_target(info->count_from_stream_output); + targ = nv50_so_target(info->indirect->count_from_stream_output); if (!targ->pq) { NOUVEAU_ERR("draw_stream_output not supported on pre-NVA0 cards\n"); return; diff --git a/src/gallium/drivers/nouveau/nv50/nv50_vbo.c b/src/gallium/drivers/nouveau/nv50/nv50_vbo.c index a8e2a1b3b27b108e9299b5d6e8f82bf8afadd889..7d9c47df037450e7c68dfc62e2c167347c4cbdd7 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_vbo.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_vbo.c @@ -702,7 +702,7 @@ nva0_draw_stream_output(struct nv50_context *nv50, const struct pipe_draw_info *info) { struct nouveau_pushbuf *push = nv50->base.pushbuf; - struct nv50_so_target *so = nv50_so_target(info->count_from_stream_output); + struct nv50_so_target *so = nv50_so_target(info->indirect->count_from_stream_output); struct nv04_resource *res = nv04_resource(so->pipe.buffer); unsigned num_instances = info->instance_count; unsigned mode = nv50_prim_gl(info->mode); @@ -874,7 +874,7 @@ nv50_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) info->mode, info->start, info->count, info->instance_count, info->index_bias, info->index_size); } else - if (unlikely(info->count_from_stream_output)) { + if (unlikely(info->indirect && info->indirect->count_from_stream_output)) { nva0_draw_stream_output(nv50, info); } else { nv50_draw_arrays(nv50, diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c b/src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c index 8287d8431b109f49d0a04257d9d0441c9734a8bf..3b44d6605c988796f4122ca94977b0a0310519be 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_vbo.c @@ -769,7 +769,7 @@ nvc0_draw_stream_output(struct nvc0_context *nvc0, const struct pipe_draw_info *info) { struct nouveau_pushbuf *push = nvc0->base.pushbuf; - struct nvc0_so_target *so = nvc0_so_target(info->count_from_stream_output); + struct nvc0_so_target *so = nvc0_so_target(info->indirect->count_from_stream_output); struct nv04_resource *res = nv04_resource(so->pipe.buffer); unsigned mode = nvc0_prim_gl(info->mode); unsigned num_instances = info->instance_count; @@ -938,7 +938,7 @@ nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) * if index count is larger and we expect repeated vertices, suggest upload. */ nvc0->vbo_push_hint = - !info->indirect && info->index_size && + (!info->indirect || info->indirect->count_from_stream_output) && info->index_size && (nvc0->vb_elt_limit >= (info->count * 2)); /* Check whether we want to switch vertex-submission mode. */ @@ -1005,7 +1005,7 @@ nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) nvc0_state_validate_3d(nvc0, ~0); - if (nvc0->vertprog->vp.need_draw_parameters && !info->indirect) { + if (nvc0->vertprog->vp.need_draw_parameters && (!info->indirect || info->indirect->count_from_stream_output)) { PUSH_SPACE(push, 9); BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3); PUSH_DATA (push, NVC0_CB_AUX_SIZE); @@ -1057,7 +1057,7 @@ nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) } if (nvc0->state.vbo_mode) { - if (info->indirect) + if (info->indirect && info->indirect->buffer) nvc0_push_vbo_indirect(nvc0, info); else nvc0_push_vbo(nvc0, info); @@ -1088,10 +1088,10 @@ nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) nvc0->base.vbo_dirty = false; } - if (unlikely(info->indirect)) { + if (unlikely(info->indirect && info->indirect->buffer)) { nvc0_draw_indirect(nvc0, info); } else - if (unlikely(info->count_from_stream_output)) { + if (unlikely(info->indirect && info->indirect->count_from_stream_output)) { nvc0_draw_stream_output(nvc0, info); } else if (info->index_size) { diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_vbo_translate.c b/src/gallium/drivers/nouveau/nvc0/nvc0_vbo_translate.c index d49a5dfd2cfd0284e5c4b190e554192d1aa57821..de08b9e6a19fb190643de0f7dcbb224959528f0b 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_vbo_translate.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_vbo_translate.c @@ -596,10 +596,10 @@ nvc0_push_vbo(struct nvc0_context *nvc0, const struct pipe_draw_info *info) nvc0_push_map_idxbuf(&ctx, nvc0, info); index_size = info->index_size; } else { - if (unlikely(info->count_from_stream_output)) { + if (unlikely(info->indirect && info->indirect->count_from_stream_output)) { struct pipe_context *pipe = &nvc0->base.pipe; struct nvc0_so_target *targ; - targ = nvc0_so_target(info->count_from_stream_output); + targ = nvc0_so_target(info->indirect->count_from_stream_output); pipe->get_query_result(pipe, targ->pq, true, (void *)&vert_count); vert_count /= targ->stride; } diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c index c451bd78f083ef69953fbcc494df63a2c17e56a8..56f10361064adaab40de88a97e174efc486a5db3 100644 --- a/src/gallium/drivers/panfrost/pan_context.c +++ b/src/gallium/drivers/panfrost/pan_context.c @@ -363,8 +363,8 @@ panfrost_draw_emit_tiler(struct panfrost_batch *batch, cfg.base_vertex_offset = info->index_bias - ctx->offset_start; cfg.index_count = info->count; } else { - cfg.index_count = info->count_from_stream_output ? - pan_so_target(info->count_from_stream_output)->offset : + cfg.index_count = info->indirect && info->indirect->count_from_stream_output ? + pan_so_target(info->indirect->count_from_stream_output)->offset : ctx->vertex_count; } } diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c index 32cc7441ff172c52de867872696ed00ff2f2b6fb..a192d457b6d43ed1781ebe6e45059b3dea89b0d0 100644 --- a/src/gallium/drivers/r600/r600_state_common.c +++ b/src/gallium/drivers/r600/r600_state_common.c @@ -2065,8 +2065,15 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info int index_bias; struct r600_shader_atomic combined_atomics[8]; uint8_t atomic_used_mask = 0; + struct pipe_draw_indirect_info *indirect = info->indirect; + struct pipe_stream_output_target *count_from_so = NULL; - if (!info->indirect && !info->count && (index_size || !info->count_from_stream_output)) { + if (indirect && indirect->count_from_stream_output) { + count_from_so = indirect->count_from_stream_output; + indirect = NULL; + } + + if (!indirect && !info->count && (index_size || !count_from_so)) { return; } @@ -2137,17 +2144,17 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info void *ptr; unsigned start, count; - if (likely(!info->indirect)) { + if (likely(!indirect)) { start = 0; count = info->count; } else { /* Have to get start/count from indirect buffer, slow path ahead... */ - struct r600_resource *indirect_resource = (struct r600_resource *)info->indirect->buffer; + struct r600_resource *indirect_resource = (struct r600_resource *)indirect->buffer; unsigned *data = r600_buffer_map_sync_with_rings(&rctx->b, indirect_resource, PIPE_MAP_READ); if (data) { - data += info->indirect->offset / sizeof(unsigned); + data += indirect->offset / sizeof(unsigned); start = data[2] * index_size; count = data[0]; } @@ -2176,7 +2183,7 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info * and the indices are emitted via PKT3_DRAW_INDEX_IMMD. * Indirect draws never use immediate indices. * Note: Instanced rendering in combination with immediate indices hangs. */ - if (has_user_indices && (R600_BIG_ENDIAN || info->indirect || + if (has_user_indices && (R600_BIG_ENDIAN || indirect || info->instance_count > 1 || info->count*index_size > 20)) { indexbuf = NULL; @@ -2194,7 +2201,7 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info if (rctx->vgt_state.vgt_multi_prim_ib_reset_en != info->primitive_restart || rctx->vgt_state.vgt_multi_prim_ib_reset_indx != info->restart_index || rctx->vgt_state.vgt_indx_offset != index_bias || - (rctx->vgt_state.last_draw_was_indirect && !info->indirect)) { + (rctx->vgt_state.last_draw_was_indirect && !indirect)) { rctx->vgt_state.vgt_multi_prim_ib_reset_en = info->primitive_restart; rctx->vgt_state.vgt_multi_prim_ib_reset_indx = info->restart_index; rctx->vgt_state.vgt_indx_offset = index_bias; @@ -2274,7 +2281,7 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info } /* Update start instance. */ - if (!info->indirect && rctx->last_start_instance != info->start_instance) { + if (!indirect && rctx->last_start_instance != info->start_instance) { radeon_set_ctl_const(cs, R_03CFF4_SQ_VTX_START_INST_LOC, info->start_instance); rctx->last_start_instance = info->start_instance; } @@ -2289,11 +2296,11 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info } /* Draw packets. */ - if (likely(!info->indirect)) { + if (likely(!indirect)) { radeon_emit(cs, PKT3(PKT3_NUM_INSTANCES, 0, 0)); radeon_emit(cs, info->instance_count); } else { - uint64_t va = r600_resource(info->indirect->buffer)->gpu_address; + uint64_t va = r600_resource(indirect->buffer)->gpu_address; assert(rctx->b.chip_class >= EVERGREEN); // Invalidate so non-indirect draw calls reset this state @@ -2307,7 +2314,7 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info radeon_emit(cs, PKT3(PKT3_NOP, 0, 0)); radeon_emit(cs, radeon_add_to_buffer_list(&rctx->b, &rctx->b.gfx, - (struct r600_resource*)info->indirect->buffer, + (struct r600_resource*)indirect->buffer, RADEON_USAGE_READ, RADEON_PRIO_DRAW_INDIRECT)); } @@ -2328,7 +2335,7 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info } else { uint64_t va = r600_resource(indexbuf)->gpu_address + index_offset; - if (likely(!info->indirect)) { + if (likely(!indirect)) { radeon_emit(cs, PKT3(PKT3_DRAW_INDEX, 3, render_cond_bit)); radeon_emit(cs, va); radeon_emit(cs, (va >> 32UL) & 0xFF); @@ -2357,13 +2364,13 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info radeon_emit(cs, max_size); radeon_emit(cs, PKT3(EG_PKT3_DRAW_INDEX_INDIRECT, 1, render_cond_bit)); - radeon_emit(cs, info->indirect->offset); + radeon_emit(cs, indirect->offset); radeon_emit(cs, V_0287F0_DI_SRC_SEL_DMA); } } } else { - if (unlikely(info->count_from_stream_output)) { - struct r600_so_target *t = (struct r600_so_target*)info->count_from_stream_output; + if (unlikely(count_from_so)) { + struct r600_so_target *t = (struct r600_so_target*)count_from_so; uint64_t va = t->buf_filled_size->gpu_address + t->buf_filled_size_offset; radeon_set_context_reg(cs, R_028B30_VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE, t->stride_in_dw); @@ -2381,16 +2388,16 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info RADEON_PRIO_SO_FILLED_SIZE)); } - if (likely(!info->indirect)) { + if (likely(!indirect)) { radeon_emit(cs, PKT3(PKT3_DRAW_INDEX_AUTO, 1, render_cond_bit)); radeon_emit(cs, info->count); } else { radeon_emit(cs, PKT3(EG_PKT3_DRAW_INDIRECT, 1, render_cond_bit)); - radeon_emit(cs, info->indirect->offset); + radeon_emit(cs, indirect->offset); } radeon_emit(cs, V_0287F0_DI_SRC_SEL_AUTO_INDEX | - (info->count_from_stream_output ? S_0287F0_USE_OPAQUE(1) : 0)); + (count_from_so ? S_0287F0_USE_OPAQUE(1) : 0)); } /* SMX returns CONTEXT_DONE too early workaround */ diff --git a/src/gallium/drivers/radeonsi/si_state_draw.c b/src/gallium/drivers/radeonsi/si_state_draw.c index 18f5c2632d3945df9a6e4c0a51748533a8a86a2d..695995a3baf6500733d3c30dfcdc1fa97aff4797 100644 --- a/src/gallium/drivers/radeonsi/si_state_draw.c +++ b/src/gallium/drivers/radeonsi/si_state_draw.c @@ -477,6 +477,22 @@ static bool si_is_line_stipple_enabled(struct si_context *sctx) (rs->polygon_mode_is_lines || util_prim_is_lines(sctx->current_rast_prim)); } +static bool num_instanced_prims_less_than(const struct pipe_draw_info *info, + const struct pipe_draw_indirect_info *indirect, + enum pipe_prim_type prim, + unsigned min_vertex_count, + unsigned instance_count, + unsigned num_prims) +{ + if (indirect) { + return indirect->buffer || + (instance_count > 1 && indirect->count_from_stream_output); + } else { + return instance_count > 1 && + si_num_prims_for_vertices(prim, min_vertex_count, info->vertices_per_patch) < num_prims; + } +} + ALWAYS_INLINE static unsigned si_get_ia_multi_vgt_param(struct si_context *sctx, const struct pipe_draw_info *info, @@ -484,6 +500,7 @@ static unsigned si_get_ia_multi_vgt_param(struct si_context *sctx, unsigned instance_count, bool primitive_restart, unsigned min_vertex_count) { + const struct pipe_draw_indirect_info *indirect = info->indirect; union si_vgt_param_key key = sctx->ia_multi_vgt_param_key; unsigned primgroup_size; unsigned ia_multi_vgt_param; @@ -497,14 +514,11 @@ static unsigned si_get_ia_multi_vgt_param(struct si_context *sctx, } key.u.prim = prim; - key.u.uses_instancing = info->indirect || instance_count > 1; + key.u.uses_instancing = (indirect && indirect->buffer) || instance_count > 1; key.u.multi_instances_smaller_than_primgroup = - info->indirect || - (instance_count > 1 && - (info->count_from_stream_output || - si_num_prims_for_vertices(prim, min_vertex_count, info->vertices_per_patch) < primgroup_size)); + num_instanced_prims_less_than(info, indirect, prim, min_vertex_count, instance_count, primgroup_size); key.u.primitive_restart = primitive_restart; - key.u.count_from_stream_output = info->count_from_stream_output != NULL; + key.u.count_from_stream_output = indirect && indirect->count_from_stream_output; key.u.line_stipple_enabled = si_is_line_stipple_enabled(sctx); ia_multi_vgt_param = @@ -521,11 +535,7 @@ static unsigned si_get_ia_multi_vgt_param(struct si_context *sctx, * only applies it to Hawaii. Do what Vulkan does. */ if (sctx->family == CHIP_HAWAII && G_028AA8_SWITCH_ON_EOI(ia_multi_vgt_param) && - (info->indirect || - (instance_count > 1 && - (info->count_from_stream_output || - si_num_prims_for_vertices(prim, min_vertex_count, info->vertices_per_patch) <= 1)))) - + num_instanced_prims_less_than(info, indirect, prim, min_vertex_count, instance_count, 2)) sctx->flags |= SI_CONTEXT_VGT_FLUSH; } @@ -771,15 +781,18 @@ static void si_emit_draw_packets(struct si_context *sctx, const struct pipe_draw unsigned sh_base_reg = sctx->shader_pointers.sh_base[PIPE_SHADER_VERTEX]; bool render_cond_bit = sctx->render_cond && !sctx->render_cond_force_off; uint32_t index_max_size = 0; + uint32_t use_opaque = 0; uint64_t index_va = 0; - if (info->count_from_stream_output) { - struct si_streamout_target *t = (struct si_streamout_target *)info->count_from_stream_output; + if (indirect && indirect->count_from_stream_output) { + struct si_streamout_target *t = (struct si_streamout_target *)indirect->count_from_stream_output; radeon_set_context_reg(cs, R_028B30_VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE, t->stride_in_dw); si_cp_copy_data(sctx, sctx->gfx_cs, COPY_DATA_REG, NULL, R_028B2C_VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE >> 2, COPY_DATA_SRC_MEM, t->buf_filled_size, t->buf_filled_size_offset); + use_opaque = S_0287F0_USE_OPAQUE(1); + indirect = NULL; } /* draw packet */ @@ -975,8 +988,7 @@ static void si_emit_draw_packets(struct si_context *sctx, const struct pipe_draw radeon_emit(cs, PKT3(PKT3_DRAW_INDEX_AUTO, 1, render_cond_bit)); radeon_emit(cs, draws[i].count); - radeon_emit(cs, V_0287F0_DI_SRC_SEL_AUTO_INDEX | - S_0287F0_USE_OPAQUE(!!info->count_from_stream_output)); + radeon_emit(cs, V_0287F0_DI_SRC_SEL_AUTO_INDEX | use_opaque); } if (num_draws > 1 && !sctx->num_vs_blit_sgprs) sctx->last_base_vertex = draws[num_draws - 1].start; @@ -1563,7 +1575,7 @@ static void si_get_draw_start_count(struct si_context *sctx, const struct pipe_d { struct pipe_draw_indirect_info *indirect = info->indirect; - if (indirect) { + if (indirect && !indirect->count_from_stream_output) { unsigned indirect_count; struct pipe_transfer *transfer; unsigned begin, end; @@ -1761,11 +1773,12 @@ static void si_multi_draw_vbo(struct pipe_context *ctx, { struct si_context *sctx = (struct si_context *)ctx; struct si_state_rasterizer *rs = sctx->queued.named.rasterizer; + struct pipe_draw_indirect_info *indirect = info->indirect; struct pipe_resource *indexbuf = info->index.resource; unsigned dirty_tex_counter, dirty_buf_counter; enum pipe_prim_type rast_prim, prim = info->mode; unsigned index_size = info->index_size; - unsigned index_offset = info->indirect ? draws[0].start * index_size : 0; + unsigned index_offset = indirect && indirect->buffer ? draws[0].start * index_size : 0; unsigned instance_count = info->instance_count; bool primitive_restart = info->primitive_restart && @@ -1776,7 +1789,7 @@ static void si_multi_draw_vbo(struct pipe_context *ctx, * no workaround for indirect draws, but we can at least skip * direct draws. */ - if (unlikely(!info->indirect && !instance_count)) + if (unlikely(!indirect && !instance_count)) return; struct si_shader_selector *vs = sctx->vs_shader.cso; @@ -1892,7 +1905,7 @@ static void si_multi_draw_vbo(struct pipe_context *ctx, } else if (info->has_user_indices) { unsigned start_offset; - assert(!info->indirect); + assert(!indirect); assert(num_draws == 1); start_offset = draws[0].start * index_size; @@ -1920,15 +1933,14 @@ static void si_multi_draw_vbo(struct pipe_context *ctx, unsigned min_direct_count = 0; unsigned total_direct_count = 0; - if (info->indirect) { - struct pipe_draw_indirect_info *indirect = info->indirect; - + if (indirect) { /* Add the buffer size for memory checking in need_cs_space. */ - si_context_add_resource_size(sctx, indirect->buffer); + if (indirect->buffer) + si_context_add_resource_size(sctx, indirect->buffer); /* Indirect buffers use TC L2 on GFX9, but not older hw. */ if (sctx->chip_class <= GFX8) { - if (si_resource(indirect->buffer)->TC_L2_dirty) { + if (indirect->buffer && si_resource(indirect->buffer)->TC_L2_dirty) { sctx->flags |= SI_CONTEXT_WB_L2; si_resource(indirect->buffer)->TC_L2_dirty = false; } @@ -1956,7 +1968,6 @@ static void si_multi_draw_vbo(struct pipe_context *ctx, : /* Add, then return true. */ (sctx->compute_num_verts_ineligible += total_direct_count, false)) && /* Add, then return false. */ - (!info->count_from_stream_output || pd_msg("draw_opaque")) && (primitive_restart ? /* Supported prim types with primitive restart: */ (prim == PIPE_PRIM_TRIANGLE_STRIP || pd_msg("bad prim type with primitive restart")) && @@ -2126,7 +2137,7 @@ static void si_multi_draw_vbo(struct pipe_context *ctx, masked_atoms |= si_get_atom_bit(sctx, &sctx->atoms.s.scissors); gfx9_scissor_bug = true; - if (info->count_from_stream_output || + if ((indirect && indirect->count_from_stream_output) || sctx->dirty_atoms & si_atoms_that_always_roll_context() || sctx->dirty_states & si_states_that_always_roll_context()) sctx->context_roll = true; diff --git a/src/gallium/drivers/softpipe/sp_draw_arrays.c b/src/gallium/drivers/softpipe/sp_draw_arrays.c index 91427348a25732c26a0460d92ea8473b36c0e64a..1dd42594da5429c590bdad81df3206f714b6dbeb 100644 --- a/src/gallium/drivers/softpipe/sp_draw_arrays.c +++ b/src/gallium/drivers/softpipe/sp_draw_arrays.c @@ -69,7 +69,7 @@ softpipe_draw_vbo(struct pipe_context *pipe, if (!softpipe_check_render_cond(sp)) return; - if (info->indirect) { + if (info->indirect && info->indirect->buffer) { util_draw_indirect(pipe, info); return; } diff --git a/src/gallium/drivers/svga/svga_pipe_draw.c b/src/gallium/drivers/svga/svga_pipe_draw.c index 06540e46dcfd401f3f7bb6857bb302ea033ae905..0986a1800d6c06c691fe297d28b3b96cc912a5c8 100644 --- a/src/gallium/drivers/svga/svga_pipe_draw.c +++ b/src/gallium/drivers/svga/svga_pipe_draw.c @@ -83,7 +83,7 @@ retry_draw_auto(struct svga_context *svga, const struct pipe_draw_info *info) { assert(svga_have_sm5(svga)); - assert(info->count_from_stream_output); + assert(info->indirect->count_from_stream_output); assert(info->instance_count == 1); /* SO drawing implies core profile and none of these prim types */ assert(info->mode != PIPE_PRIM_QUADS && @@ -117,7 +117,7 @@ retry_draw_auto(struct svga_context *svga, 0, /* start instance */ 1, /* only 1 instance supported */ NULL, /* indirect drawing info */ - info->count_from_stream_output)); + info->indirect->count_from_stream_output)); return PIPE_OK; } @@ -132,7 +132,7 @@ retry_draw_indirect(struct svga_context *svga, const struct pipe_draw_info *info) { assert(svga_have_sm5(svga)); - assert(info->indirect); + assert(info->indirect && info->indirect->buffer); /* indirect drawing implies core profile and none of these prim types */ assert(info->mode != PIPE_PRIM_QUADS && info->mode != PIPE_PRIM_QUAD_STRIP && @@ -273,8 +273,7 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) goto done; } - if (!info->indirect && !info->count_from_stream_output && - !u_trim_pipe_prim(info->mode, &count)) + if (!info->indirect && !u_trim_pipe_prim(info->mode, &count)) goto done; needed_swtnl = svga->state.sw.need_swtnl; @@ -318,7 +317,7 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) svga_is_using_flat_shading(svga), svga->curr.rast->templ.flatshade_first); - if (info->count_from_stream_output) { + if (info->indirect && info->indirect->count_from_stream_output) { unsigned stream = 0; assert(count == 0); @@ -332,7 +331,7 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) /* Check the stream index of the specified stream output target */ for (unsigned i = 0; i < ARRAY_SIZE(svga->so_targets); i++) { - if (svga->vcount_so_targets[i] == info->count_from_stream_output) { + if (svga->vcount_so_targets[i] == info->indirect->count_from_stream_output) { stream = (svga->vcount_buffer_stream >> (i * 4)) & 0xf; break; } @@ -342,10 +341,10 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) } } - if (info->count_from_stream_output && count == 0) { + if (info->indirect && info->indirect->count_from_stream_output && count == 0) { ret = retry_draw_auto(svga, info); } - else if (info->indirect) { + else if (info->indirect && info->indirect->buffer) { ret = retry_draw_indirect(svga, info); } else if (info->index_size) { diff --git a/src/gallium/drivers/swr/swr_draw.cpp b/src/gallium/drivers/swr/swr_draw.cpp index 399821c32eaba9acb66262adb8535242437b2c43..0bf29ef77a3cb18dad6f1394a662b334edf5f2c7 100644 --- a/src/gallium/drivers/swr/swr_draw.cpp +++ b/src/gallium/drivers/swr/swr_draw.cpp @@ -41,7 +41,7 @@ swr_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) { struct swr_context *ctx = swr_context(pipe); - if (!info->count_from_stream_output && !info->indirect && + if (!info->indirect && !info->primitive_restart && !u_trim_pipe_prim(info->mode, (unsigned*)&info->count)) return; @@ -49,7 +49,7 @@ swr_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) if (!swr_check_render_cond(pipe)) return; - if (info->indirect) { + if (info->indirect && info->indirect->buffer) { util_draw_indirect(pipe, info); return; } @@ -66,11 +66,12 @@ swr_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) struct pipe_draw_info resolved_info; /* DrawTransformFeedback */ - if (info->count_from_stream_output) { + if (info->indirect && info->indirect->count_from_stream_output) { // trick copied from softpipe to modify const struct *info memcpy(&resolved_info, (void*)info, sizeof(struct pipe_draw_info)); resolved_info.count = ctx->so_primCounter * resolved_info.vertices_per_patch; resolved_info.max_index = resolved_info.count - 1; + resolved_info.indirect = NULL; info = &resolved_info; } diff --git a/src/gallium/drivers/tegra/tegra_context.c b/src/gallium/drivers/tegra/tegra_context.c index c3ae90e4d6db95ad2e9acb59af0e2394da08a7c7..1b15ba2fce10baca29ca1fa595f82b4b8f6f5f9d 100644 --- a/src/gallium/drivers/tegra/tegra_context.c +++ b/src/gallium/drivers/tegra/tegra_context.c @@ -52,10 +52,10 @@ tegra_draw_vbo(struct pipe_context *pcontext, struct pipe_draw_indirect_info indirect; struct pipe_draw_info info; - if (pinfo && (pinfo->indirect || pinfo->index_size)) { + if (pinfo && ((pinfo->indirect && pinfo->indirect->buffer) || pinfo->index_size)) { memcpy(&info, pinfo, sizeof(info)); - if (pinfo->indirect) { + if (pinfo->indirect && pinfo->indirect->buffer) { memcpy(&indirect, pinfo->indirect, sizeof(indirect)); indirect.buffer = tegra_resource_unwrap(info.indirect->buffer); info.indirect = &indirect; diff --git a/src/gallium/drivers/v3d/v3dx_draw.c b/src/gallium/drivers/v3d/v3dx_draw.c index 968918ab70f298afe1dbfccae891aebeaa274046..1957f88d127fe13b09b0e29aadcd87235d11b9a0 100644 --- a/src/gallium/drivers/v3d/v3dx_draw.c +++ b/src/gallium/drivers/v3d/v3dx_draw.c @@ -1088,7 +1088,7 @@ v3d_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) { struct v3d_context *v3d = v3d_context(pctx); - if (!info->count_from_stream_output && !info->indirect && + if (!info->indirect && !info->primitive_restart && !u_trim_pipe_prim(info->mode, (unsigned*)&info->count)) return; @@ -1127,7 +1127,7 @@ v3d_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) for (int s = 0; s < PIPE_SHADER_COMPUTE; s++) v3d_predraw_check_stage_inputs(pctx, s); - if (info->indirect) { + if (info->indirect && info->indirect->buffer) { v3d_flush_jobs_writing_resource(v3d, info->indirect->buffer, V3D_FLUSH_DEFAULT, false); } @@ -1155,7 +1155,7 @@ v3d_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) * on the last submitted render, rather than tracking the last * rendering to each texture's BO. */ - if (v3d->tex[PIPE_SHADER_VERTEX].num_textures || info->indirect) { + if (v3d->tex[PIPE_SHADER_VERTEX].num_textures || (info->indirect && info->indirect->buffer)) { perf_debug("Blocking binner on last render " "due to vertex texturing or indirect drawing.\n"); job->submit.in_sync_bcl = v3d->out_sync; @@ -1284,7 +1284,7 @@ v3d_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) } #endif - if (info->indirect) { + if (info->indirect && info->indirect->buffer) { cl_emit(&job->bcl, INDIRECT_INDEXED_INSTANCED_PRIM_LIST, prim) { prim.index_type = ffs(info->index_size) - 1; #if V3D_VERSION < 40 @@ -1335,7 +1335,7 @@ v3d_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) if (info->has_user_indices) pipe_resource_reference(&prsc, NULL); } else { - if (info->indirect) { + if (info->indirect && info->indirect->buffer) { cl_emit(&job->bcl, INDIRECT_VERTEX_ARRAY_INSTANCED_PRIMS, prim) { prim.mode = hw_prim_type | prim_tf_enable; prim.number_of_draw_indirect_array_records = info->indirect->draw_count; @@ -1346,7 +1346,8 @@ v3d_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) } } else if (info->instance_count > 1) { struct pipe_stream_output_target *so = - info->count_from_stream_output; + info->indirect && info->indirect->count_from_stream_output ? + info->indirect->count_from_stream_output : NULL; uint32_t vert_count = so ? v3d_stream_output_target_get_vertex_count(so) : info->count; @@ -1358,7 +1359,8 @@ v3d_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) } } else { struct pipe_stream_output_target *so = - info->count_from_stream_output; + info->indirect && info->indirect->count_from_stream_output ? + info->indirect->count_from_stream_output : NULL; uint32_t vert_count = so ? v3d_stream_output_target_get_vertex_count(so) : info->count; diff --git a/src/gallium/drivers/vc4/vc4_draw.c b/src/gallium/drivers/vc4/vc4_draw.c index b4523bb12500b39b93811c598f8cbb4470d9bd08..bd54df0cdda541643017d130392c818602e13c03 100644 --- a/src/gallium/drivers/vc4/vc4_draw.c +++ b/src/gallium/drivers/vc4/vc4_draw.c @@ -291,7 +291,7 @@ vc4_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) struct vc4_context *vc4 = vc4_context(pctx); struct pipe_draw_info local_info; - if (!info->count_from_stream_output && !info->indirect && + if (!info->indirect && !info->primitive_restart && !u_trim_pipe_prim(info->mode, (unsigned*)&info->count)) return; diff --git a/src/gallium/drivers/virgl/virgl_context.c b/src/gallium/drivers/virgl/virgl_context.c index 4fabc89b1bd510067dc542b3697a49467525b22c..8aaceda2fb4e62bb5940ce6706c97131db188631 100644 --- a/src/gallium/drivers/virgl/virgl_context.c +++ b/src/gallium/drivers/virgl/virgl_context.c @@ -855,7 +855,7 @@ static void virgl_draw_vbo(struct pipe_context *ctx, struct virgl_indexbuf ib = {}; struct pipe_draw_info info = *dinfo; - if (!dinfo->count_from_stream_output && !dinfo->indirect && + if (!dinfo->indirect && !dinfo->primitive_restart && !u_trim_pipe_prim(dinfo->mode, (unsigned*)&dinfo->count)) return; diff --git a/src/gallium/drivers/virgl/virgl_encode.c b/src/gallium/drivers/virgl/virgl_encode.c index ee75debddf49964fe42f8a2f4cadd99c82e58b4d..dc51178f802b94221b347e2f71e3268ea51321cc 100644 --- a/src/gallium/drivers/virgl/virgl_encode.c +++ b/src/gallium/drivers/virgl/virgl_encode.c @@ -712,7 +712,7 @@ int virgl_encoder_draw_vbo(struct virgl_context *ctx, uint32_t length = VIRGL_DRAW_VBO_SIZE; if (info->mode == PIPE_PRIM_PATCHES) length = VIRGL_DRAW_VBO_SIZE_TESS; - if (info->indirect) + if (info->indirect && info->indirect->buffer) length = VIRGL_DRAW_VBO_SIZE_INDIRECT; virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_DRAW_VBO, 0, length)); virgl_encoder_write_dword(ctx->cbuf, info->start); @@ -726,8 +726,8 @@ int virgl_encoder_draw_vbo(struct virgl_context *ctx, virgl_encoder_write_dword(ctx->cbuf, info->restart_index); virgl_encoder_write_dword(ctx->cbuf, info->min_index); virgl_encoder_write_dword(ctx->cbuf, info->max_index); - if (info->count_from_stream_output) - virgl_encoder_write_dword(ctx->cbuf, info->count_from_stream_output->buffer_size); + if (info->indirect && info->indirect->count_from_stream_output) + virgl_encoder_write_dword(ctx->cbuf, info->indirect->count_from_stream_output->buffer_size); else virgl_encoder_write_dword(ctx->cbuf, 0); if (length >= VIRGL_DRAW_VBO_SIZE_TESS) { diff --git a/src/gallium/drivers/zink/zink_draw.c b/src/gallium/drivers/zink/zink_draw.c index 9ff6e6420a9e9c566e2c58754cfcba262f0af225..ae57550fed0af06c8103327d34d3dda10d3f4aa0 100644 --- a/src/gallium/drivers/zink/zink_draw.c +++ b/src/gallium/drivers/zink/zink_draw.c @@ -214,7 +214,9 @@ zink_draw_vbo(struct pipe_context *pctx, struct zink_screen *screen = zink_screen(pctx->screen); struct zink_rasterizer_state *rast_state = ctx->rast_state; struct zink_depth_stencil_alpha_state *dsa_state = ctx->dsa_state; - struct zink_so_target *so_target = zink_so_target(dinfo->count_from_stream_output); + struct zink_so_target *so_target = + dinfo->indirect && dinfo->indirect->count_from_stream_output ? + zink_so_target(dinfo->indirect->count_from_stream_output) : NULL; VkBuffer counter_buffers[PIPE_MAX_SO_OUTPUTS]; VkDeviceSize counter_buffer_offsets[PIPE_MAX_SO_OUTPUTS] = {}; bool need_index_buffer_unref = false; @@ -514,7 +516,7 @@ zink_draw_vbo(struct pipe_context *pctx, struct zink_resource *res = zink_resource(index_buffer); vkCmdBindIndexBuffer(batch->cmdbuf, res->buffer, index_offset, index_type); zink_batch_reference_resource_rw(batch, res, false); - if (dinfo->indirect) { + if (dinfo->indirect && dinfo->indirect->buffer) { struct zink_resource *indirect = zink_resource(dinfo->indirect->buffer); zink_batch_reference_resource_rw(batch, indirect, false); vkCmdDrawIndexedIndirect(batch->cmdbuf, indirect->buffer, dinfo->indirect->offset, dinfo->indirect->draw_count, dinfo->indirect->stride); @@ -528,7 +530,7 @@ zink_draw_vbo(struct pipe_context *pctx, screen->vk_CmdDrawIndirectByteCountEXT(batch->cmdbuf, dinfo->instance_count, dinfo->start_instance, zink_resource(so_target->counter_buffer)->buffer, so_target->counter_buffer_offset, 0, MIN2(so_target->stride, screen->info.tf_props.maxTransformFeedbackBufferDataStride)); - } else if (dinfo->indirect) { + } else if (dinfo->indirect && dinfo->indirect->buffer) { struct zink_resource *indirect = zink_resource(dinfo->indirect->buffer); zink_batch_reference_resource_rw(batch, indirect, false); vkCmdDrawIndirect(batch->cmdbuf, indirect->buffer, dinfo->indirect->offset, dinfo->indirect->draw_count, dinfo->indirect->stride); diff --git a/src/gallium/frontends/nine/device9.c b/src/gallium/frontends/nine/device9.c index 36f0c8f1266c5b2169a5f253d204262aef62d36c..a7587cc95170773195349ea50d43bee9ecd746e7 100644 --- a/src/gallium/frontends/nine/device9.c +++ b/src/gallium/frontends/nine/device9.c @@ -3174,7 +3174,6 @@ NineDevice9_ProcessVertices( struct NineDevice9 *This, draw.start_instance = 0; draw.primitive_restart = FALSE; draw.restart_index = 0; - draw.count_from_stream_output = NULL; draw.indirect = NULL; draw.instance_count = 1; draw.index_size = 0; diff --git a/src/gallium/frontends/nine/nine_state.c b/src/gallium/frontends/nine/nine_state.c index 9dae199d5f80f98dffb1880649638f38734ab6c9..e4d72c62ae8774230d2d70e1aa8bec29000d0c94 100644 --- a/src/gallium/frontends/nine/nine_state.c +++ b/src/gallium/frontends/nine/nine_state.c @@ -2318,7 +2318,6 @@ init_draw_info(struct pipe_draw_info *info, info->primitive_restart = FALSE; info->has_user_indices = FALSE; info->restart_index = 0; - info->count_from_stream_output = NULL; info->indirect = NULL; } diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h index fbf463618da2f75be263ad0de714142b580e0827..ad5701ba9c54c76d68ce8235ee3defe90dcb76cd 100644 --- a/src/gallium/include/pipe/p_state.h +++ b/src/gallium/include/pipe/p_state.h @@ -712,6 +712,8 @@ struct pipe_draw_indirect_info * uint32_t start; * uint32_t start_instance; * }; + * + * If NULL, count_from_stream_output != NULL. */ struct pipe_resource *buffer; @@ -719,6 +721,22 @@ struct pipe_draw_indirect_info * is to be used as the real draw_count. */ struct pipe_resource *indirect_draw_count; + + /** + * Stream output target. If not NULL, it's used to provide the 'count' + * parameter based on the number vertices captured by the stream output + * stage. (or generally, based on the number of bytes captured) + * + * Only 'mode', 'start_instance', and 'instance_count' are taken into + * account, all the other variables from pipe_draw_info are ignored. + * + * 'start' is implicitly 0 and 'count' is set as discussed above. + * The draw command is non-indexed. + * + * Note that this only provides the count. The vertex buffers must + * be set via set_vertex_buffers manually. + */ + struct pipe_stream_output_target *count_from_stream_output; }; struct pipe_draw_start_count { @@ -777,22 +795,6 @@ struct pipe_draw_info } index; struct pipe_draw_indirect_info *indirect; /**< Indirect draw. */ - - /** - * Stream output target. If not NULL, it's used to provide the 'count' - * parameter based on the number vertices captured by the stream output - * stage. (or generally, based on the number of bytes captured) - * - * Only 'mode', 'start_instance', and 'instance_count' are taken into - * account, all the other variables from pipe_draw_info are ignored. - * - * 'start' is implicitly 0 and 'count' is set as discussed above. - * The draw command is non-indexed. - * - * Note that this only provides the count. The vertex buffers must - * be set via set_vertex_buffers manually. - */ - struct pipe_stream_output_target *count_from_stream_output; }; diff --git a/src/mesa/state_tracker/st_cb_xformfb.c b/src/mesa/state_tracker/st_cb_xformfb.c index 4126e64345b35d0c5a624181d50501c60c2b4b1d..8ecf91c5e2b40c3d09587acb324b55b99c1ac71a 100644 --- a/src/mesa/state_tracker/st_cb_xformfb.c +++ b/src/mesa/state_tracker/st_cb_xformfb.c @@ -214,7 +214,8 @@ st_end_transform_feedback(struct gl_context *ctx, bool st_transform_feedback_draw_init(struct gl_transform_feedback_object *obj, - unsigned stream, struct pipe_draw_info *out) + unsigned stream, + struct pipe_draw_indirect_info *out) { struct st_transform_feedback_object *sobj = st_transform_feedback_object(obj); diff --git a/src/mesa/state_tracker/st_cb_xformfb.h b/src/mesa/state_tracker/st_cb_xformfb.h index 5db4094755201cc1d825df7556c37831ea5a7bca..635ebd8eed695c4736d77b46ff13ceec87da3eec 100644 --- a/src/mesa/state_tracker/st_cb_xformfb.h +++ b/src/mesa/state_tracker/st_cb_xformfb.h @@ -31,14 +31,15 @@ struct dd_function_table; struct gl_transform_feedback_object; -struct pipe_draw_info; +struct pipe_draw_indirect_info; extern void st_init_xformfb_functions(struct dd_function_table *functions); extern bool st_transform_feedback_draw_init(struct gl_transform_feedback_object *obj, - unsigned stream, struct pipe_draw_info *out); + unsigned stream, + struct pipe_draw_indirect_info *out); #endif /* ST_CB_XFORMFB_H */ diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c index 1745a8d194805a01b773da413a191ad0da4ac226..ef8d5b0b1493693730cc9d416bcd921f35c6abfa 100644 --- a/src/mesa/state_tracker/st_draw.c +++ b/src/mesa/state_tracker/st_draw.c @@ -177,7 +177,6 @@ st_draw_vbo(struct gl_context *ctx, info.primitive_restart = false; info.vertices_per_patch = ctx->TessCtrlProgram.patch_vertices; info.indirect = NULL; - info.count_from_stream_output = NULL; info.restart_index = 0; info.start_instance = base_instance; info.instance_count = num_instances; @@ -330,15 +329,18 @@ st_draw_transform_feedback(struct gl_context *ctx, GLenum mode, { struct st_context *st = st_context(ctx); struct pipe_draw_info info; + struct pipe_draw_indirect_info indirect; prepare_draw(st, ctx); + memset(&indirect, 0, sizeof(indirect)); util_draw_init_info(&info); info.start = 0; /* index offset / index size */ info.max_index = ~0u; /* so that u_vbuf can tell that it's unknown */ info.mode = translate_prim(ctx, mode); info.vertices_per_patch = ctx->TessCtrlProgram.patch_vertices; info.instance_count = num_instances; + info.indirect = &indirect; if (ST_DEBUG & DEBUG_DRAW) { debug_printf("st/draw transform feedback: mode %s\n", @@ -347,7 +349,7 @@ st_draw_transform_feedback(struct gl_context *ctx, GLenum mode, /* Transform feedback drawing is always non-indexed. */ /* Set info.count_from_stream_output. */ - if (!st_transform_feedback_draw_init(tfb_vertcount, stream, &info)) + if (!st_transform_feedback_draw_init(tfb_vertcount, stream, &indirect)) return; cso_draw_vbo(st->cso_context, &info);