diff --git a/src/asahi/lib/agx_ppp.h b/src/asahi/lib/agx_ppp.h
index bb35b2df0b1..92ec3aa2a0b 100644
--- a/src/asahi/lib/agx_ppp.h
+++ b/src/asahi/lib/agx_ppp.h
@@ -36,8 +36,15 @@ agx_ppp_update_size(struct AGX_PPP_HEADER *present)
PPP_CASE(fragment_back_face_2, FRAGMENT_FACE_2);
PPP_CASE(fragment_back_stencil, FRAGMENT_STENCIL);
PPP_CASE(depth_bias_scissor, DEPTH_BIAS_SCISSOR);
- PPP_CASE(region_clip, REGION_CLIP);
- PPP_CASE(viewport, VIEWPORT);
+
+ if (present->region_clip)
+ size += present->viewport_count * AGX_REGION_CLIP_LENGTH;
+
+ if (present->viewport) {
+ size += AGX_VIEWPORT_CONTROL_LENGTH +
+ (present->viewport_count * AGX_VIEWPORT_LENGTH);
+ }
+
PPP_CASE(w_clamp, W_CLAMP);
PPP_CASE(output_select, OUTPUT_SELECT);
PPP_CASE(varying_counts_32, VARYING_COUNTS);
diff --git a/src/asahi/lib/cmdbuf.xml b/src/asahi/lib/cmdbuf.xml
index d1734e5bd60..ca01ffa2be3 100644
--- a/src/asahi/lib/cmdbuf.xml
+++ b/src/asahi/lib/cmdbuf.xml
@@ -430,6 +430,7 @@
+
@@ -445,7 +446,7 @@
-
+
@@ -453,6 +454,11 @@
+
+
+
+
diff --git a/src/asahi/lib/decode.c b/src/asahi/lib/decode.c
index ffe2295c2da..f336449a111 100644
--- a/src/asahi/lib/decode.c
+++ b/src/asahi/lib/decode.c
@@ -517,8 +517,38 @@ agxdecode_record(uint64_t va, size_t size, bool verbose, decoder_params *params)
PPP_PRINT(map, fragment_back_face_2, FRAGMENT_FACE_2, "Back face 2");
PPP_PRINT(map, fragment_back_stencil, FRAGMENT_STENCIL, "Back stencil");
PPP_PRINT(map, depth_bias_scissor, DEPTH_BIAS_SCISSOR, "Depth bias/scissor");
- PPP_PRINT(map, region_clip, REGION_CLIP, "Region clip");
- PPP_PRINT(map, viewport, VIEWPORT, "Viewport");
+
+ if (hdr.region_clip) {
+ if (((map + (AGX_REGION_CLIP_LENGTH * hdr.viewport_count)) >
+ (base + size))) {
+ fprintf(agxdecode_dump_stream, "Buffer overrun in PPP update\n");
+ return;
+ }
+
+ for (unsigned i = 0; i < hdr.viewport_count; ++i) {
+ DUMP_CL(REGION_CLIP, map, "Region clip");
+ map += AGX_REGION_CLIP_LENGTH;
+ fflush(agxdecode_dump_stream);
+ }
+ }
+
+ if (hdr.viewport) {
+ if (((map + AGX_VIEWPORT_CONTROL_LENGTH +
+ (AGX_VIEWPORT_LENGTH * hdr.viewport_count)) > (base + size))) {
+ fprintf(agxdecode_dump_stream, "Buffer overrun in PPP update\n");
+ return;
+ }
+
+ DUMP_CL(VIEWPORT_CONTROL, map, "Viewport control");
+ map += AGX_VIEWPORT_CONTROL_LENGTH;
+
+ for (unsigned i = 0; i < hdr.viewport_count; ++i) {
+ DUMP_CL(VIEWPORT, map, "Viewport");
+ map += AGX_VIEWPORT_LENGTH;
+ fflush(agxdecode_dump_stream);
+ }
+ }
+
PPP_PRINT(map, w_clamp, W_CLAMP, "W clamp");
PPP_PRINT(map, output_select, OUTPUT_SELECT, "Output select");
PPP_PRINT(map, varying_counts_32, VARYING_COUNTS, "Varying counts 32");
diff --git a/src/gallium/drivers/asahi/agx_state.c b/src/gallium/drivers/asahi/agx_state.c
index d15f9242333..76f36509e40 100644
--- a/src/gallium/drivers/asahi/agx_state.c
+++ b/src/gallium/drivers/asahi/agx_state.c
@@ -1040,6 +1040,7 @@ agx_upload_viewport_scissor(struct agx_pool *pool, struct agx_batch *batch,
.depth_bias_scissor = true,
.region_clip = true,
.viewport = true,
+ .viewport_count = 1,
});
agx_ppp_push(&ppp, DEPTH_BIAS_SCISSOR, cfg) {
@@ -1058,6 +1059,9 @@ agx_upload_viewport_scissor(struct agx_pool *pool, struct agx_batch *batch,
cfg.max_y = DIV_ROUND_UP(MAX2(maxy, 1), 32);
}
+ agx_ppp_push(&ppp, VIEWPORT_CONTROL, cfg)
+ ;
+
agx_ppp_push(&ppp, VIEWPORT, cfg) {
cfg.translate_x = vp->translate[0];
cfg.translate_y = vp->translate[1];
@@ -2951,6 +2955,7 @@ agx_batch_init_state(struct agx_batch *batch)
.occlusion_query_2 = true,
.output_unknown = true,
.varying_word_2 = true,
+ .viewport_count = 1, /* irrelevant */
});
/* clang-format off */
@@ -3139,6 +3144,7 @@ agx_encode_state(struct agx_batch *batch, uint8_t *out, bool is_lines,
IS_DIRTY(FS) || varyings_dirty || IS_DIRTY(SAMPLE_MASK),
.occlusion_query = IS_DIRTY(QUERY),
.output_size = IS_DIRTY(VS_PROG),
+ .viewport_count = 1, /* irrelevant */
};
struct agx_ppp_update ppp = agx_new_ppp_update(pool, dirty);