From f285a1220ea5a8e9ef32683a957bfb2aec728dd6 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Thu, 27 May 2021 22:51:09 -0400 Subject: [PATCH] asahi: Implement scissors and scissor to viewport Construct a scissor descriptor correpsonding to the intersection of the framebuffer, the viewport, and the region selected for scissoring by the app. Use the intersected scissor in the "clip tile" fields in the viewport. Select this scissor descriptor from the command stream. Signed-off-by: Alyssa Rosenzweig Part-of: --- src/gallium/drivers/asahi/agx_state.c | 93 ++++++++++++++++++++------- 1 file changed, 70 insertions(+), 23 deletions(-) diff --git a/src/gallium/drivers/asahi/agx_state.c b/src/gallium/drivers/asahi/agx_state.c index f84c9f32a60..4ca466a796c 100644 --- a/src/gallium/drivers/asahi/agx_state.c +++ b/src/gallium/drivers/asahi/agx_state.c @@ -452,36 +452,71 @@ agx_set_viewport_states(struct pipe_context *pctx, ctx->viewport = *vp; } -static uint64_t -agx_upload_viewport(struct agx_pool *pool, - const struct pipe_viewport_state *vp) +struct agx_viewport_scissor { + uint64_t viewport; + unsigned scissor; +}; + +static struct agx_viewport_scissor +agx_upload_viewport_scissor(struct agx_pool *pool, + struct agx_batch *batch, + const struct pipe_viewport_state *vp, + const struct pipe_scissor_state *ss) { struct agx_ptr T = agx_pool_alloc_aligned(pool, AGX_VIEWPORT_LENGTH, 64); - float vp_minx = vp->translate[0] - fabsf(vp->scale[0]); - float vp_maxx = vp->translate[0] + fabsf(vp->scale[0]); - float vp_miny = vp->translate[1] - fabsf(vp->scale[1]); - float vp_maxy = vp->translate[1] + fabsf(vp->scale[1]); + unsigned minx = CLAMP((int) vp->translate[0] - fabsf(vp->scale[0]), 0, batch->width); + unsigned maxx = CLAMP((int) vp->translate[0] + fabsf(vp->scale[0]), 0, batch->width); + unsigned miny = CLAMP((int) vp->translate[1] - fabsf(vp->scale[1]), 0, batch->height); + unsigned maxy = CLAMP((int) vp->translate[1] + fabsf(vp->scale[1]), 0, batch->height); - float near_z, far_z; - util_viewport_zmin_zmax(vp, false, &near_z, &far_z); + if (ss) { + minx = MAX2(ss->minx, minx); + miny = MAX2(ss->miny, miny); + maxx = MIN2(ss->maxx, maxx); + maxy = MIN2(ss->maxy, maxy); + } + + assert(maxx > minx && maxy > miny); + + float minz, maxz; + util_viewport_zmin_zmax(vp, false, &minz, &maxz); agx_pack(T.cpu, VIEWPORT, cfg) { - cfg.min_tile_x = vp_minx / 32; - cfg.min_tile_y = vp_miny / 32; - cfg.max_tile_x = MAX2(ceilf(vp_maxx / 32.0), 1.0); - cfg.max_tile_y = MAX2(ceilf(vp_maxy / 32.0), 1.0); + cfg.min_tile_x = minx / 32; + cfg.min_tile_y = miny / 32; + cfg.max_tile_x = DIV_ROUND_UP(maxx, 32); + cfg.max_tile_y = DIV_ROUND_UP(maxy, 32); cfg.clip_tile = true; cfg.translate_x = vp->translate[0]; cfg.translate_y = vp->translate[1]; cfg.scale_x = vp->scale[0]; cfg.scale_y = vp->scale[1]; - cfg.translate_z = near_z; - cfg.scale_z = far_z - near_z; + + /* Assumes [0, 1] clip coordinates. If half-z is not in use, lower_half_z + * is called to ensure this works. */ + cfg.translate_z = minz; + cfg.scale_z = maxz - minz; }; - return T.gpu; + /* Allocate a new scissor descriptor */ + struct agx_scissor_packed *ptr = batch->scissor.bo->ptr.cpu; + unsigned index = (batch->scissor.count++); + + agx_pack(ptr + index, SCISSOR, cfg) { + cfg.min_x = minx; + cfg.min_y = miny; + cfg.min_z = minz; + cfg.max_x = maxx; + cfg.max_y = maxy; + cfg.max_z = maxz; + } + + return (struct agx_viewport_scissor) { + .viewport = T.gpu, + .scissor = index + }; } /* A framebuffer state can be reused across batches, so it doesn't make sense @@ -1056,6 +1091,11 @@ demo_rasterizer(struct agx_context *ctx, struct agx_pool *pool) cfg.front.disable_depth_write = ctx->zs.disable_z_write; cfg.back.disable_depth_write = ctx->zs.disable_z_write; + + /* Always enable scissoring so we may scissor to the viewport (TODO: + * optimize this out if the viewport is the default and the app does not + * use the scissor test) */ + cfg.scissor_enable = true; }; return t.gpu; @@ -1096,13 +1136,15 @@ demo_unk12(struct agx_pool *pool) } static uint64_t -demo_unk14(struct agx_pool *pool) +agx_set_scissor_index(struct agx_pool *pool, unsigned index) { - uint32_t unk[] = { - 0x100, 0x0, + struct agx_ptr T = agx_pool_alloc_aligned(pool, AGX_SET_SCISSOR_LENGTH, 64); + + agx_pack(T.cpu, SET_SCISSOR, cfg) { + cfg.index = index; }; - return agx_pool_upload(pool, unk, sizeof(unk)); + return T.gpu; } static void @@ -1144,12 +1186,17 @@ agx_encode_state(struct agx_context *ctx, uint8_t *out, agx_push_record(&out, 7, demo_rasterizer(ctx, pool)); agx_push_record(&out, 5, demo_unk11(pool, is_lines, reads_tib)); - if (ctx->dirty & AGX_DIRTY_VIEWPORT) - agx_push_record(&out, 10, agx_upload_viewport(pool, &ctx->viewport)); + if (ctx->dirty & (AGX_DIRTY_VIEWPORT | AGX_DIRTY_SCISSOR)) { + struct agx_viewport_scissor vps = agx_upload_viewport_scissor(pool, + ctx->batch, &ctx->viewport, + ctx->rast->base.scissor ? &ctx->scissor : NULL); + + agx_push_record(&out, 10, vps.viewport); + agx_push_record(&out, 2, agx_set_scissor_index(pool, vps.scissor)); + } agx_push_record(&out, 3, demo_unk12(pool)); agx_push_record(&out, 2, agx_pool_upload(pool, ctx->rast->cull, sizeof(ctx->rast->cull))); - agx_push_record(&out, 2, demo_unk14(pool)); return (out - 1); // XXX: alignment fixup, or something }