gallium: move count_from_stream_output into pipe_draw_indirect_info
This removes some overhead from tc_draw_vbo and increases the maximum number of draws per batch from 153 to 192 in u_threaded_context. Reviewed-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7441>
This commit is contained in:
parent
238ee7b801
commit
1a717dca04
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue