Skip to content

Commit

Permalink
util/rectpack: refactor to use standard mempools
Browse files Browse the repository at this point in the history
  • Loading branch information
Akaricchi committed Jun 5, 2024
1 parent f9c2748 commit a8322f5
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 99 deletions.
17 changes: 10 additions & 7 deletions src/lasers/draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ static struct {
} fb;

struct {
MemArena arena;
Allocator alloc;
RectPack rectpack;
MemArena arena;
RectPackSectionPool rpspool;
} packer;

struct {
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
21 changes: 17 additions & 4 deletions src/resource/font.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -128,6 +129,8 @@ static struct {
Texture *render_tex;
Framebuffer *render_buf;
SpriteSheetAnchor spritesheets;
MemArena arena;
RectPackSectionPool rpspool;

struct {
SDL_mutex *new_face;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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];
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down
107 changes: 41 additions & 66 deletions src/util/rectpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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);
Expand All @@ -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);

Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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),
Expand All @@ -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,
Expand All @@ -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);

Expand All @@ -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),
Expand All @@ -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),
Expand All @@ -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;
Expand All @@ -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) {
Expand Down
Loading

0 comments on commit a8322f5

Please sign in to comment.