From 722ca5761908280a095f03930c842d8247d9490e Mon Sep 17 00:00:00 2001 From: Christian Gmeiner Date: Fri, 24 Jan 2025 15:08:29 +0100 Subject: [PATCH] etnaviv: Add support for KHR_partial_update The damage region can be useful to optimize the "resolve" step that we have on imx6q (GC2000) because there isn't any tiling compatible with both render and scanout or an any GPU when scanning out a linear buffer since we don't support linear PE. This improves fps for e.g `weston-simple-egl` by factor 2 (~30 fps -> ~60 fps). Signed-off-by: Christian Gmeiner Reviewed-by: Lucas Stach Part-of: --- docs/relnotes/new_features.txt | 1 + .../drivers/etnaviv/etnaviv_clear_blit.c | 11 ++- .../drivers/etnaviv/etnaviv_resource.c | 90 +++++++++++++++++++ .../drivers/etnaviv/etnaviv_resource.h | 3 + 4 files changed, 103 insertions(+), 2 deletions(-) diff --git a/docs/relnotes/new_features.txt b/docs/relnotes/new_features.txt index b71b492c126..e77298691aa 100644 --- a/docs/relnotes/new_features.txt +++ b/docs/relnotes/new_features.txt @@ -24,3 +24,4 @@ EXT_shader_framebuffer_image_fetch on v3d EXT_shader_framebuffer_image_fetch_coherent on v3d KHR_blend_equation_advanced on v3d KHR_blend_equation_advanced_coherent on v3d +KHR_partial_update on etnaviv diff --git a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c index 65d641c966b..c06053fab2e 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c +++ b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c @@ -189,8 +189,15 @@ etna_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc) struct etna_resource *rsc = etna_resource(prsc); if (rsc->render) { - if (etna_resource_older(rsc, etna_resource(rsc->render))) - etna_copy_resource(pctx, prsc, rsc->render, 0, 0); + if (etna_resource_older(rsc, etna_resource(rsc->render))) { + if (rsc->damage) { + for (unsigned i = 0; i < rsc->num_damage; i++) { + etna_copy_resource_box(pctx, prsc, rsc->render, 0, 0, &rsc->damage[i]); + } + } else { + etna_copy_resource(pctx, prsc, rsc->render, 0, 0); + } + } } else if (!etna_resource_ext_ts(rsc) && etna_resource_needs_flush(rsc)) { etna_copy_resource(pctx, prsc, prsc, 0, 0); } diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c index f309b73d714..32ecf617fef 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.c +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c @@ -28,9 +28,11 @@ #include "etnaviv_context.h" #include "etnaviv_debug.h" +#include "etnaviv_rs.h" #include "etnaviv_screen.h" #include "etnaviv_translate.h" +#include "util/box.h" #include "util/hash_table.h" #include "util/u_inlines.h" #include "util/u_memory.h" @@ -599,6 +601,7 @@ etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) for (unsigned i = 0; i < ETNA_NUM_LOD; i++) FREE(rsc->levels[i].patch_offsets); + FREE(rsc->damage); FREE(rsc); } @@ -915,6 +918,92 @@ etna_resource_needs_flush(struct etna_resource *rsc) return false; } +static void +etna_resource_set_damage_region(struct pipe_screen *pscreen, + struct pipe_resource *prsc, + unsigned int nrects, + const struct pipe_box *rects) +{ + struct etna_resource *rsc = etna_resource(prsc); + struct etna_screen *screen = etna_screen(pscreen); + unsigned int i; + + if (rsc->damage) { + FREE(rsc->damage); + rsc->damage = NULL; + } + + /* Bail out if there is no render resource to blit from. */ + if (!rsc->render) + return; + + if (!nrects) + return; + + /* Check for full damage. */ + for (i = 0; i < nrects; i++) { + if (rects[i].x <= 0 && rects[i].y <= 0 && + rects[i].x + rects[i].width >= prsc->width0 && + rects[i].y + rects[i].height >= prsc->height0) + return; + } + + rsc->damage = CALLOC(nrects, sizeof(*rsc->damage)); + if (!rsc->damage) + return; + + for (i = 0; i < nrects; i++) { + struct pipe_box *damage = &rsc->damage[i]; + + *damage = rects[i]; + + /* The damage we get from EGL uses a lower-left origin but the hardware + * uses upper-left so we need to flip it. */ + damage->y = prsc->height0 - (damage->y + damage->height); + + if (!screen->specs.use_blt) + etna_align_box_for_rs(screen, etna_resource(rsc->render), damage); + } + + bool progress; + + do { + progress = false; + + for (unsigned i = 0; i < nrects; i++) { + for (unsigned j = i + 1; j < nrects; j++) { + if (u_box_test_intersection_2d(&rsc->damage[i], &rsc->damage[j])) { + + /* Union them into the i-th slot */ + u_box_union_2d(&rsc->damage[i], + &rsc->damage[i], + &rsc->damage[j]); + + /* Remove the j-th rect by shifting everything above it down 1. */ + if (j < (nrects - 1)) { + memmove(&rsc->damage[j], + &rsc->damage[j + 1], + (nrects - (j + 1)) * sizeof(rsc->damage[0])); + } + + /* We have merged one rect, so we have one less overall. */ + nrects--; + + /* We must restart because rsc->damage[i] has changed and + * might now intersect with some earlier rectangle. */ + progress = true; + break; + } + } + + if (progress) + break; + } + } while (progress); + + rsc->num_damage = nrects; +} + void etna_resource_screen_init(struct pipe_screen *pscreen) { @@ -926,4 +1015,5 @@ etna_resource_screen_init(struct pipe_screen *pscreen) pscreen->resource_get_param = etna_resource_get_param; pscreen->resource_changed = etna_resource_changed; pscreen->resource_destroy = etna_resource_destroy; + pscreen->set_damage_region = etna_resource_set_damage_region; } diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.h b/src/gallium/drivers/etnaviv/etnaviv_resource.h index 6c159e2d723..94071a1f75e 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.h +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.h @@ -220,6 +220,9 @@ struct etna_resource { bool explicit_flush; /* resource is shared outside of the screen */ bool shared; + + struct pipe_box *damage; + unsigned num_damage; }; /* returns TRUE if a is newer than b */