Module: Mesa Branch: main Commit: 08c612b5ceef4168f42110d980667f0c766b6794 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=08c612b5ceef4168f42110d980667f0c766b6794
Author: Alyssa Rosenzweig <[email protected]> Date: Mon Sep 5 20:11:26 2022 -0400 asahi: Allocate new cmdbufs if out of space Instead of crashing when we run out of space in the command buffer, allocate a new buffer, jump to it with the STREAM_LINK command, and use it to write new commands. Signed-off-by: Alyssa Rosenzweig <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18421> --- src/gallium/drivers/asahi/agx_pipe.c | 2 ++ src/gallium/drivers/asahi/agx_state.c | 53 +++++++++++++++++++++++++++++++++-- src/gallium/drivers/asahi/agx_state.h | 1 + 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/gallium/drivers/asahi/agx_pipe.c b/src/gallium/drivers/asahi/agx_pipe.c index 8a38fb8f994..9b59e235b38 100644 --- a/src/gallium/drivers/asahi/agx_pipe.c +++ b/src/gallium/drivers/asahi/agx_pipe.c @@ -573,6 +573,7 @@ agx_flush(struct pipe_context *pctx, ctx->batch->draw = 0; ctx->batch->load = 0; ctx->batch->encoder_current = ctx->batch->encoder->ptr.cpu; + ctx->batch->encoder_end = ctx->batch->encoder_current + ctx->batch->encoder->size; ctx->batch->scissor.count = 0; agx_dirty_all(ctx); @@ -623,6 +624,7 @@ agx_create_context(struct pipe_screen *screen, agx_device(screen), AGX_MEMORY_TYPE_SHADER, true); ctx->batch->encoder = agx_bo_create(agx_device(screen), 0x80000, AGX_MEMORY_TYPE_FRAMEBUFFER); ctx->batch->encoder_current = ctx->batch->encoder->ptr.cpu; + ctx->batch->encoder_end = ctx->batch->encoder_current + ctx->batch->encoder->size; ctx->batch->scissor.bo = agx_bo_create(agx_device(screen), 0x80000, AGX_MEMORY_TYPE_FRAMEBUFFER); ctx->batch->depth_bias.bo = agx_bo_create(agx_device(screen), 0x80000, AGX_MEMORY_TYPE_FRAMEBUFFER); diff --git a/src/gallium/drivers/asahi/agx_state.c b/src/gallium/drivers/asahi/agx_state.c index 917af844688..140c7494342 100644 --- a/src/gallium/drivers/asahi/agx_state.c +++ b/src/gallium/drivers/asahi/agx_state.c @@ -1503,11 +1503,14 @@ agx_point_object_type(struct agx_rasterizer *rast) AGX_OBJECT_TYPE_POINT_SPRITE_UV10; } +#define MAX_PPP_UPDATES 2 + static uint8_t * agx_encode_state(struct agx_context *ctx, uint8_t *out, bool is_lines, bool is_points) { struct agx_rasterizer *rast = ctx->rast; + unsigned ppp_updates = 0; #define IS_DIRTY(ST) !!(ctx->dirty & AGX_DIRTY_##ST) @@ -1572,6 +1575,7 @@ agx_encode_state(struct agx_context *ctx, uint8_t *out, ctx->rast->base.flatshade_first); varyings_dirty = true; + ppp_updates++; } bool object_type_dirty = IS_DIRTY(PRIM) || @@ -1703,9 +1707,11 @@ agx_encode_state(struct agx_context *ctx, uint8_t *out, } agx_ppp_fini(&out, &ppp); + ppp_updates++; #undef IS_DIRTY + assert(ppp_updates <= MAX_PPP_UPDATES); return out; } @@ -1754,6 +1760,30 @@ agx_scissor_culls_everything(struct agx_context *ctx) ((ss.minx == ss.maxx) || (ss.miny == ss.maxy)); } +static void +agx_ensure_cmdbuf_has_space(struct agx_batch *batch, size_t space) +{ + /* If there is room in the command buffer, we're done */ + if (likely((batch->encoder_end - batch->encoder_current) >= space)) + return; + + /* Otherwise, we need to allocate a new command buffer. We use memory owned + * by the batch to simplify lifetime management for the BO. + */ + size_t size = 65536; + struct agx_ptr T = agx_pool_alloc_aligned(&batch->pool, size, 256); + + /* Jump from the old command buffer to the new command buffer */ + agx_pack(batch->encoder_current, STREAM_LINK, cfg) { + cfg.target_lo = T.gpu & BITFIELD_MASK(32); + cfg.target_hi = T.gpu >> 32; + } + + /* Swap out the command buffer */ + batch->encoder_current = T.cpu; + batch->encoder_end = batch->encoder_current + size; +} + static void agx_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info, unsigned drawid_offset, @@ -1806,8 +1836,25 @@ agx_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info, agx_batch_add_bo(batch, ctx->vs->bo); agx_batch_add_bo(batch, ctx->fs->bo); - ptrdiff_t encoder_use = batch->encoder_current - (uint8_t *) batch->encoder->ptr.cpu; - assert((encoder_use + 1024) < batch->encoder->size && "todo: how to expand encoder?"); + /* When we approach the end of a command buffer, cycle it out for a new one. + * We only need to do this once per draw as long as we conservatively + * estimate the maximum bytes of VDM commands that this draw will emit. + */ + agx_ensure_cmdbuf_has_space(batch, + (AGX_VDM_STATE_LENGTH * 2) + + (AGX_PPP_STATE_LENGTH * MAX_PPP_UPDATES) + + AGX_VDM_STATE_RESTART_INDEX_LENGTH + + AGX_VDM_STATE_VERTEX_SHADER_WORD_0_LENGTH + + AGX_VDM_STATE_VERTEX_SHADER_WORD_1_LENGTH + + AGX_VDM_STATE_VERTEX_OUTPUTS_LENGTH + + AGX_VDM_STATE_VERTEX_UNKNOWN_LENGTH + + 4 /* padding */ + + AGX_INDEX_LIST_LENGTH + + AGX_INDEX_LIST_BUFFER_LO_LENGTH + + AGX_INDEX_LIST_COUNT_LENGTH + + AGX_INDEX_LIST_INSTANCES_LENGTH + + AGX_INDEX_LIST_START_LENGTH + + AGX_INDEX_LIST_BUFFER_SIZE_LENGTH); uint8_t *out = agx_encode_state(ctx, batch->encoder_current, reduced_prim == PIPE_PRIM_LINES, @@ -1875,6 +1922,8 @@ agx_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info, } batch->encoder_current = out; + assert(batch->encoder_current <= batch->encoder_end && + "Failed to reserve sufficient space in encoder"); ctx->dirty = 0; } diff --git a/src/gallium/drivers/asahi/agx_state.h b/src/gallium/drivers/asahi/agx_state.h index fd50cf887eb..157473077aa 100644 --- a/src/gallium/drivers/asahi/agx_state.h +++ b/src/gallium/drivers/asahi/agx_state.h @@ -121,6 +121,7 @@ struct agx_batch { struct agx_pool pool, pipeline_pool; struct agx_bo *encoder; uint8_t *encoder_current; + uint8_t *encoder_end; struct agx_array scissor, depth_bias; };
