From a8322f5e1d6c3d20aac7377163ae38e4fed2f3b5 Mon Sep 17 00:00:00 2001 From: Andrei Alexeyev Date: Wed, 5 Jun 2024 23:53:30 +0200 Subject: [PATCH] util/rectpack: refactor to use standard mempools --- src/lasers/draw.c | 17 ++++--- src/resource/font.c | 21 +++++++-- src/util/rectpack.c | 107 +++++++++++++++++--------------------------- src/util/rectpack.h | 41 ++++++++--------- 4 files changed, 87 insertions(+), 99 deletions(-) diff --git a/src/lasers/draw.c b/src/lasers/draw.c index 99b2810a9b..770961ba6e 100644 --- a/src/lasers/draw.c +++ b/src/lasers/draw.c @@ -122,9 +122,9 @@ static struct { } fb; struct { - MemArena arena; - Allocator alloc; RectPack rectpack; + MemArena arena; + RectPackSectionPool rpspool; } packer; struct { @@ -257,18 +257,17 @@ void laserdraw_preload(ResourceGroup *rg) { } static void laserdraw_init_packer(void) { - rectpack_init(&ldraw.packer.rectpack, &ldraw.packer.alloc, - PACKING_SPACE_SIZE_W, PACKING_SPACE_SIZE_H); + rectpack_init(&ldraw.packer.rectpack, PACKING_SPACE_SIZE_W, PACKING_SPACE_SIZE_H); } static void laserdraw_reset_packer(void) { marena_reset(&ldraw.packer.arena); + ldraw.packer.rpspool = (RectPackSectionPool) {}; laserdraw_init_packer(); } void laserdraw_init(void) { marena_init(&ldraw.packer.arena, 0); - allocator_init_from_arena(&ldraw.packer.alloc, &ldraw.packer.arena); laserdraw_init_packer(); dynarray_ensure_capacity(&ldraw.queue, 64); @@ -300,7 +299,6 @@ void laserdraw_init(void) { void laserdraw_shutdown(void) { dynarray_free_data(&ldraw.queue); - allocator_deinit(&ldraw.packer.alloc); marena_deinit(&ldraw.packer.arena); fbmgr_group_destroy(ldraw.fb.group); r_vertex_array_destroy(ldraw.pass1.va); @@ -333,7 +331,12 @@ static bool laserdraw_pack_laser(Laser *l, cmplxf *out_ofs, bool *rotated) { FloatExtent bbox_size = { .as_cmplx = laser_packed_dimensions(l) }; RectPackSection *section = rectpack_add( - &ldraw.packer.rectpack, bbox_size.w, bbox_size.h, true); + &ldraw.packer.rectpack, + (RectPackSectionSource) { + .arena = &ldraw.packer.arena, + .pool = &ldraw.packer.rpspool, + }, + bbox_size.w, bbox_size.h, true); if(!section) { return false; diff --git a/src/resource/font.c b/src/resource/font.c index 95217be4d4..92e680f1d3 100644 --- a/src/resource/font.c +++ b/src/resource/font.c @@ -11,6 +11,7 @@ #include "config.h" #include "dynarray.h" #include "events.h" +#include "memory/arena.h" #include "renderer/api.h" #include "util.h" #include "util/glm.h" @@ -128,6 +129,8 @@ static struct { Texture *render_tex; Framebuffer *render_buf; SpriteSheetAnchor spritesheets; + MemArena arena; + RectPackSectionPool rpspool; struct { SDL_mutex *new_face; @@ -191,6 +194,8 @@ static void *ft_realloc(FT_Memory mem, long cur_size, long new_size, void *block static void init_fonts(void) { FT_Error err; + marena_init(&globals.arena, sizeof(RectPackSection) * 128); + static typeof(*(FT_Memory)0) ft_mem = { .alloc = ft_alloc, .free = ft_free, @@ -252,6 +257,7 @@ static void shutdown_fonts(void) { FT_Done_Library(globals.lib); SDL_DestroyMutex(globals.mutex.new_face); SDL_DestroyMutex(globals.mutex.done_face); + marena_deinit(&globals.arena); } static char *font_path(const char *name) { @@ -393,6 +399,13 @@ void font_set_kerning_enabled(Font *font, bool newval) { #define SS_TEXTURE_TYPE TEX_TYPE_RGB_8 #define SS_TEXTURE_FLAGS 0 +INLINE RectPackSectionSource rps_source(void) { + return (RectPackSectionSource) { + .arena = &globals.arena, + .pool = &globals.rpspool, + }; +} + static SpriteSheet *add_spritesheet(SpriteSheetAnchor *spritesheets) { auto ss = ALLOC(SpriteSheet, { .tex = r_texture_create(&(TextureParams) { @@ -409,7 +422,7 @@ static SpriteSheet *add_spritesheet(SpriteSheetAnchor *spritesheets) { }) }); - rectpack_init(&ss->rectpack, &default_allocator, SS_WIDTH, SS_HEIGHT); + rectpack_init(&ss->rectpack, SS_WIDTH, SS_HEIGHT); #ifdef DEBUG char buf[128]; @@ -429,7 +442,7 @@ static bool add_glyph_to_spritesheet(Glyph *glyph, Pixmap *pixmap, SpriteSheet * uint padded_w = pixmap->width + 2 * GLYPH_SPRITE_PADDING; uint padded_h = pixmap->height + 2 * GLYPH_SPRITE_PADDING; - glyph->spritesheet_section = rectpack_add(&ss->rectpack, padded_w, padded_h); + glyph->spritesheet_section = rectpack_add(&ss->rectpack, rps_source(), padded_w, padded_h, false); if(glyph->spritesheet_section == NULL) { return false; @@ -496,7 +509,7 @@ static const char *pixmode_name(FT_Pixel_Mode mode) { static void delete_spritesheet(SpriteSheetAnchor *spritesheets, SpriteSheet *ss) { r_texture_destroy(ss->tex); - rectpack_deinit(&ss->rectpack); + assert(rectpack_is_empty(&ss->rectpack)); alist_unlink(spritesheets, ss); mem_free(ss); } @@ -738,7 +751,7 @@ static void wipe_glyph_cache(Font *font) { RectPackSection *section = g->spritesheet_section; assume(section != NULL); - rectpack_reclaim(rp, section); + rectpack_reclaim(rp, rps_source(), section); if(rectpack_is_empty(rp)) { delete_spritesheet(&globals.spritesheets, ss); diff --git a/src/util/rectpack.c b/src/util/rectpack.c index f34a12d4a2..838138f40a 100644 --- a/src/util/rectpack.c +++ b/src/util/rectpack.c @@ -35,28 +35,20 @@ static inline void section_make_used(RectPack *rp, RectPackSection *s) { s->next = s->prev = s; } -static RectPackSection *acquire_section(RectPack *rp) { - RectPackSection *s = list_pop(&rp->sections_freelist); - - if(!s) { - s = ALLOC_VIA(rp->allocator, typeof(*s)); - } - - *s = (RectPackSection) { }; - return s; +static RectPackSection *acquire_section(RectPackSectionSource secsrc) { + return mempool_acquire(secsrc.pool, secsrc.arena); } -static void release_section(RectPack *rp, RectPackSection *s) { - list_push(&rp->sections_freelist, s); +static void release_section(RectPackSectionSource secsrc, RectPackSection *s) { + mempool_release(secsrc.pool, s); } -void rectpack_init(RectPack *rp, Allocator *alloc, double width, double height) { +void rectpack_init(RectPack *rp, double width, double height) { *rp = (RectPack) { .root.rect = { .top_left = CMPLX(0, 0), .bottom_right = CMPLX(width, height), }, - .allocator = alloc, }; list_push(&rp->unused_sections, &rp->root); assert(rectpack_is_empty(rp)); @@ -71,35 +63,6 @@ bool rectpack_is_empty(RectPack *rp) { return false; } -static void delete_subsections(RectPack *rp, RectPackSection *restrict s) { - if(s->children[0] != NULL) { - assume(s->children[1] != NULL); - assume(s->children[0]->parent == s); - assume(s->children[1]->parent == s); - - delete_subsections(rp, s->children[0]); - release_section(rp, s->children[0]); - s->children[0] = NULL; - - delete_subsections(rp, s->children[1]); - release_section(rp, s->children[1]); - s->children[1] = NULL; - } -} - -void rectpack_reset(RectPack *rp) { - delete_subsections(rp, &rp->root); -} - -void rectpack_deinit(RectPack *rp) { - delete_subsections(rp, &rp->root); - Allocator *alloc = rp->allocator; - - for(RectPackSection *s; (s = list_pop(&rp->sections_freelist));) { - allocator_free(alloc, s); - } -} - static double section_fitness(RectPackSection *s, double w, double h) { double sw = rect_width(s->rect); double sh = rect_height(s->rect); @@ -111,7 +74,7 @@ static double section_fitness(RectPackSection *s, double w, double h) { return sw * sh - w * h; // best area fit } -void rectpack_reclaim(RectPack *rp, RectPackSection *s) { +void rectpack_reclaim(RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s) { assume(s->children[0] == NULL); assume(s->children[1] == NULL); @@ -133,14 +96,14 @@ void rectpack_reclaim(RectPack *rp, RectPackSection *s) { // NOTE: the following frees s->sibling and s, in unspecified order - release_section(rp, parent->children[0]); + release_section(secsrc, parent->children[0]); parent->children[0] = NULL; - release_section(rp, parent->children[1]); + release_section(secsrc, parent->children[1]); parent->children[1] = NULL; if(parent != NULL) { - rectpack_reclaim(rp, parent); + rectpack_reclaim(rp, secsrc, parent); } RP_DEBUG("done reclaiming parent of %p", (void*)s); @@ -154,7 +117,7 @@ void rectpack_reclaim(RectPack *rp, RectPackSection *s) { } static RectPackSection *select_fittest_section( - RectPack *rp, double *width, double *height, bool allow_rotation + RectPack *rp, RectPackSectionSource secsrc, double *width, double *height, bool allow_rotation ) { RectPackSection *best = NULL; double fitness = DBL_MAX; @@ -201,10 +164,14 @@ static RectPackSection *select_fittest_section( return best; } -static RectPackSection *split_horizontal(RectPack *rp, RectPackSection *s, double width, double height); -static RectPackSection *split_vertical(RectPack *rp, RectPackSection *s, double width, double height); +static RectPackSection *split_horizontal( + RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s, double width, double height); +static RectPackSection *split_vertical( + RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s, double width, double height); -static RectPackSection *split_horizontal(RectPack *rp, RectPackSection *s, double width, double height) { +static RectPackSection *split_horizontal( + RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s, double width, double height +) { RP_DEBUG("spliting section %p of size %gx%g for rect %gx%g", (void*)s, rect_width(s->rect), rect_height(s->rect), width, height); assert(rect_width(s->rect) >= width); @@ -213,10 +180,10 @@ static RectPackSection *split_horizontal(RectPack *rp, RectPackSection *s, doubl if(rect_height(s->rect) == height) { assert(rect_width(s->rect) > width); RP_DEBUG("delegated to vertical split"); - return split_vertical(rp, s, width, height); + return split_vertical(rp, secsrc, s, width, height); } - auto sub = acquire_section(rp); + auto sub = acquire_section(secsrc); rect_set_xywh(&sub->rect, rect_x(s->rect), rect_y(s->rect), @@ -228,7 +195,7 @@ static RectPackSection *split_horizontal(RectPack *rp, RectPackSection *s, doubl sub->parent = s; s->children[0] = sub; - s->children[1] = acquire_section(rp); + s->children[1] = acquire_section(secsrc); rect_set_xywh(&s->children[1]->rect, rect_x(s->rect), rect_y(s->rect) + height, @@ -247,13 +214,15 @@ static RectPackSection *split_horizontal(RectPack *rp, RectPackSection *s, doubl ); if(rect_width(sub->rect) != width) { - sub = split_vertical(rp, sub, width, height); + sub = split_vertical(rp, secsrc, sub, width, height); } return sub; } -static RectPackSection *split_vertical(RectPack *rp, RectPackSection *s, double width, double height) { +static RectPackSection *split_vertical( + RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s, double width, double height +) { assert(rect_width(s->rect) >= width); assert(rect_height(s->rect) >= height); @@ -262,10 +231,10 @@ static RectPackSection *split_vertical(RectPack *rp, RectPackSection *s, double if(rect_width(s->rect) == width) { assert(rect_height(s->rect) > height); RP_DEBUG("delegated to horizontal split"); - return split_horizontal(rp, s, width, height); + return split_horizontal(rp, secsrc, s, width, height); } - auto sub = acquire_section(rp); + auto sub = acquire_section(secsrc); rect_set_xywh(&sub->rect, rect_x(s->rect), rect_y(s->rect), @@ -277,7 +246,7 @@ static RectPackSection *split_vertical(RectPack *rp, RectPackSection *s, double sub->parent = s; s->children[0] = sub; - s->children[1] = acquire_section(rp); + s->children[1] = acquire_section(secsrc); rect_set_xywh(&s->children[1]->rect, rect_x(s->rect) + width, rect_y(s->rect), @@ -296,26 +265,32 @@ static RectPackSection *split_vertical(RectPack *rp, RectPackSection *s, double ); if(rect_height(sub->rect) != height) { - sub = split_horizontal(rp, sub, width, height); + sub = split_horizontal(rp, secsrc, sub, width, height); } return sub; } -static RectPackSection *split(RectPack *rp, RectPackSection *s, double width, double height) { +static RectPackSection *split( + RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s, double width, double height +) { // short leftover axis split if(rect_width(s->rect) - width < rect_height(s->rect) - height) { - return split_horizontal(rp, s, width, height); + return split_horizontal(rp, secsrc, s, width, height); } else { - return split_vertical(rp, s, width, height); + return split_vertical(rp, secsrc, s, width, height); } } -RectPackSection *(rectpack_add)( - RectPack *rp, double width, double height, bool allow_rotation +RectPackSection *rectpack_add( + RectPack *rp, + RectPackSectionSource secsrc, + double width, + double height, + bool allow_rotation ) { - RectPackSection *s = select_fittest_section(rp, &width, &height, allow_rotation); + RectPackSection *s = select_fittest_section(rp, secsrc, &width, &height, allow_rotation); if(s == NULL) { return NULL; @@ -327,7 +302,7 @@ RectPackSection *(rectpack_add)( return s; } - return split(rp, s, width, height); + return split(rp, secsrc, s, width, height); } Rect rectpack_section_rect(RectPackSection *s) { diff --git a/src/util/rectpack.h b/src/util/rectpack.h index 81bfb2eb9e..9a74648779 100644 --- a/src/util/rectpack.h +++ b/src/util/rectpack.h @@ -11,50 +11,47 @@ #include "geometry.h" #include "list.h" -#include "memory/allocator.h" +#include "memory/mempool.h" typedef struct RectPack RectPack; typedef struct RectPackSection RectPackSection; +typedef MEMPOOL(RectPackSection) RectPackSectionPool; +typedef struct RectPackSectionSource RectPackSectionSource; struct RectPackSection { LIST_INTERFACE(RectPackSection); - Rect rect; RectPackSection *parent; RectPackSection *sibling; RectPackSection *children[2]; + Rect rect; }; struct RectPack { RectPackSection root; RectPackSection *unused_sections; - RectPackSection *sections_freelist; - Allocator *allocator; }; -void rectpack_init(RectPack *rp, Allocator *alloc, double width, double height) - attr_nonnull_all; - -void rectpack_reset(RectPack *rp) - attr_nonnull(1); - -void rectpack_deinit(RectPack *rp) - attr_nonnull(1); +struct RectPackSectionSource { + RectPackSectionPool *pool; + MemArena *arena; +}; -RectPackSection *rectpack_add(RectPack *rp, double width, double height, bool allow_rotation) - attr_nonnull(1); +void rectpack_init(RectPack *rp, double width, double height) + attr_nonnull_all; -#define _rectpack_add_3(rp, width, height) \ - rectpack_add(rp, width, height, false) -#define _rectpack_add_4(rp, width, height, allow_rotation) \ - rectpack_add(rp, width, height, allow_rotation) -#define rectpack_add(...) \ - MACROHAX_OVERLOAD_NARGS(_rectpack_add_, __VA_ARGS__)(__VA_ARGS__) +RectPackSection *rectpack_add( + RectPack *rp, + RectPackSectionSource secsrc, + double width, + double height, + bool allow_rotation +) attr_nonnull(1); Rect rectpack_section_rect(RectPackSection *s) attr_nonnull(1); -void rectpack_reclaim(RectPack *rp, RectPackSection *s) - attr_nonnull(1, 2); +void rectpack_reclaim(RectPack *rp, RectPackSectionSource secsrc, RectPackSection *s) + attr_nonnull(1, 3); bool rectpack_is_empty(RectPack *rp) attr_nonnull(1);