From cc1dea6ec94aad181c05c157ca679c5dc1c1004d Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Sun, 24 Nov 2019 13:06:03 -0800 Subject: montage: add montage module This is somewhat unfinished as it uses the generic tiled fragmenter that's not interested in appearances but prioritizes total coverage and simplicity. Montage should have its own tiler that can produce non-square and even non-uniform tile dimensions, prioritizing filling the screen with mostly-uniform tiles. But that's a TODO item, this is good enough for now and exercises some fragment details previously irrelevant and often ignored/broken in modules. The pixbounce module in particular seems completely broken with small fragment sizes. --- src/Makefile.am | 2 +- src/modules/Makefile.am | 2 +- src/modules/montage/Makefile.am | 3 + src/modules/montage/montage.c | 168 ++++++++++++++++++++++++++++++++++++++++ src/rototiller.c | 2 + 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 src/modules/montage/Makefile.am create mode 100644 src/modules/montage/montage.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 48b0a4c..2501c95 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,4 +4,4 @@ rototiller_SOURCES = fb.c fb.h fps.c fps.h rototiller.c rototiller.h sdl_fb.c se if ENABLE_DRM rototiller_SOURCES += drm_fb.c endif -rototiller_LDADD = modules/flui2d/libflui2d.a modules/julia/libjulia.a modules/pixbounce/libpixbounce.a modules/plasma/libplasma.a modules/ray/libray.a modules/roto/libroto.a modules/rtv/librtv.a modules/snow/libsnow.a modules/sparkler/libsparkler.a modules/stars/libstars.a modules/submit/libsubmit.a modules/swab/libswab.a libs/grid/libgrid.a libs/ray/libray.a libs/txt/libtxt.a libs/ascii/libascii.a libs/din/libdin.a -lm +rototiller_LDADD = modules/flui2d/libflui2d.a modules/julia/libjulia.a modules/montage/libmontage.a modules/pixbounce/libpixbounce.a modules/plasma/libplasma.a modules/ray/libray.a modules/roto/libroto.a modules/rtv/librtv.a modules/snow/libsnow.a modules/sparkler/libsparkler.a modules/stars/libstars.a modules/submit/libsubmit.a modules/swab/libswab.a libs/grid/libgrid.a libs/ray/libray.a libs/txt/libtxt.a libs/ascii/libascii.a libs/din/libdin.a -lm diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am index 0ab81b7..1622814 100644 --- a/src/modules/Makefile.am +++ b/src/modules/Makefile.am @@ -1 +1 @@ -SUBDIRS = flui2d julia pixbounce plasma ray roto rtv snow sparkler stars submit swab +SUBDIRS = flui2d julia montage pixbounce plasma ray roto rtv snow sparkler stars submit swab diff --git a/src/modules/montage/Makefile.am b/src/modules/montage/Makefile.am new file mode 100644 index 0000000..7465510 --- /dev/null +++ b/src/modules/montage/Makefile.am @@ -0,0 +1,3 @@ +noinst_LIBRARIES = libmontage.a +libmontage_a_SOURCES = montage.c +libmontage_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/modules/montage/montage.c b/src/modules/montage/montage.c new file mode 100644 index 0000000..068c6e0 --- /dev/null +++ b/src/modules/montage/montage.c @@ -0,0 +1,168 @@ +#include +#include +#include + +#include "fb.h" +#include "rototiller.h" +#include "settings.h" +#include "util.h" + +/* Copyright (C) 2019 - Vito Caputo */ + +typedef struct montage_context_t { + const rototiller_module_t **modules; + const rototiller_module_t *rtv_module; + void **contexts; + size_t n_modules; + unsigned n_cpus; +} montage_context_t; + +static void setup_next_module(montage_context_t *ctxt); +static void * montage_create_context(unsigned num_cpus); +static void montage_destroy_context(void *context); +static void montage_prepare_frame(void *context, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter); +static void montage_render_fragment(void *context, unsigned cpu, fb_fragment_t *fragment); + + +rototiller_module_t montage_module = { + .create_context = montage_create_context, + .destroy_context = montage_destroy_context, + .prepare_frame = montage_prepare_frame, + .render_fragment = montage_render_fragment, + .name = "montage", + .description = "Rototiller montage", + .author = "Vito Caputo ", + .license = "GPLv2", +}; + + +static int skip_module(montage_context_t *ctxt, const rototiller_module_t *module) +{ + /* prevent recursion */ + if (module == &montage_module) + return 1; + + /* also prevents recursion, as rtv could run montage... */ + if (module == ctxt->rtv_module) + return 1; + + return 0; +} + + +static void * montage_create_context(unsigned num_cpus) +{ + montage_context_t *ctxt = calloc(1, sizeof(montage_context_t)); + + ctxt->n_cpus = num_cpus; + rototiller_get_modules(&ctxt->modules, &ctxt->n_modules); + + ctxt->contexts = calloc(ctxt->n_modules, sizeof(void *)); + if (!ctxt->contexts) { + free(ctxt); + + return NULL; + } + + ctxt->rtv_module = rototiller_lookup_module("rtv"); + + for (int i = 0; i < ctxt->n_modules; i++) { + const rototiller_module_t *module = ctxt->modules[i]; + + if (skip_module(ctxt, module)) + continue; + + if (module->create_context) /* FIXME errors */ + ctxt->contexts[i] = module->create_context(num_cpus); + } + + return ctxt; +} + + +static void montage_destroy_context(void *context) +{ + montage_context_t *ctxt = context; + + for (int i = 0; i < ctxt->n_modules; i++) { + const rototiller_module_t *module = ctxt->modules[i]; + + if (skip_module(ctxt, module)) + continue; + + if (!ctxt->contexts[i]) + continue; + + module->destroy_context(ctxt->contexts[i]); + } + + free(context); +} + + +/* The fragmenter in montage is serving double-duty: + * 1. it divides the frame into subfragments for threaded rendering + * 2. it determines which modules will be rendered where via fragment->number + */ +static int montage_fragmenter(void *context, const fb_fragment_t *fragment, unsigned number, fb_fragment_t *res_fragment) +{ + montage_context_t *ctxt = context; + float root = sqrtf((float)ctxt->n_modules); + int ret; + + ret = fb_fragment_tile_single(fragment, fragment->frame_height / root, number, res_fragment); + if (!ret) + return 0; + + if (number >= ctxt->n_modules) + return 0; + + /* as these tiles are frames of their own rather than subfragments, override these values */ + res_fragment->x = res_fragment->y = 0; + res_fragment->frame_width = res_fragment->width; + res_fragment->frame_height = res_fragment->height; + + return ret; +} + + + +static void montage_prepare_frame(void *context, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +{ + montage_context_t *ctxt = context; + + *res_fragmenter = montage_fragmenter; +} + + +static void montage_render_fragment(void *context, unsigned cpu, fb_fragment_t *fragment) +{ + montage_context_t *ctxt = context; + const rototiller_module_t *module = ctxt->modules[fragment->number]; + + if (skip_module(ctxt, module)) + return; + + /* since we're *already* in a threaded render of tiles, no further + * threading within the montage tiles is desirable, so the per-module + * render is done explicitly serially here in an open-coded ad-hoc + * fashion for now. FIXME TODO: move this into rototiller.c + */ + if (module->prepare_frame) { + rototiller_fragmenter_t unused; + + /* XXX FIXME: ignoring the fragmenter here is a violation of the module API, + * rototiller.c should have a module render interface with explicit non-threading + * that still does all the necessary fragmenting as needed. + * + * Today, I can get away with this, because montage is the only module that's + * sensitive to this aspect of the API and it skips itself. + */ + + module->prepare_frame(ctxt->contexts[fragment->number], 1, fragment, &unused); + } + + if (module->render_fragment) + module->render_fragment(ctxt->contexts[fragment->number], 0, fragment); +} + diff --git a/src/rototiller.c b/src/rototiller.c index 4d6bd79..42b9007 100644 --- a/src/rototiller.c +++ b/src/rototiller.c @@ -34,6 +34,7 @@ fb_ops_t *fb_ops; extern rototiller_module_t flui2d_module; extern rototiller_module_t julia_module; +extern rototiller_module_t montage_module; extern rototiller_module_t pixbounce_module; extern rototiller_module_t plasma_module; extern rototiller_module_t ray_module; @@ -48,6 +49,7 @@ extern rototiller_module_t swab_module; static const rototiller_module_t *modules[] = { &flui2d_module, &julia_module, + &montage_module, &pixbounce_module, &plasma_module, &ray_module, -- cgit v1.2.1