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 */