diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2021-02-14 22:43:08 -0800 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2021-02-14 22:51:37 -0800 |
commit | 11b87c843e20f66bd68e02353ba4a1072e1230a6 (patch) | |
tree | 15458ff0ac2b61b51517fb26ca3cd4b148c2a96f /src | |
parent | 950d6abb1ffd126a3200044de31b631ac987ed7e (diff) |
*: split rototiller.[ch] into lib and main
This is a first approximation of separating the core modules and
threaded rendering from the cli-centric rototiller program and
its sdl+drm video backends.
Unfortunately this seemed to require switching over to libtool
archives (.la) to permit consolidating the per-lib and
per-module .a files into the librototiller.a and linking just
with librototiller.a to depend on the aggregate of
libs+modules+librototiller-glue in a simple fashion.
If an alternative to .la comes up I will switch over to it,
using libtool really slows down the build process.
Those are implementation/build system details though. What's
important in these changes is establishing something resembling a
librototiller API boundary, enabling creating alternative
frontends which vendor this tree as a submodule and link just to
librototiller.{la,a} for all the modules+threaded rendering of
them, while providing their own fb_ops_t for outputting into, and
their own settings applicators for driving the modules setup.
Diffstat (limited to 'src')
30 files changed, 466 insertions, 396 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index d65eb5c..c2e8653 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,14 @@ SUBDIRS = libs modules + +noinst_LTLIBRARIES = librototiller.la +librototiller_la_SOURCES = fb.c fb.h knobs.h rototiller.c rototiller.h settings.h settings.c threads.c threads.h util.c util.h +librototiller_la_CPPFLAGS = -I@top_srcdir@/src +librototiller_la_LIBADD = modules/compose/libcompose.la modules/drizzle/libdrizzle.la modules/flui2d/libflui2d.la modules/julia/libjulia.la modules/meta2d/libmeta2d.la modules/montage/libmontage.la modules/pixbounce/libpixbounce.la modules/plasma/libplasma.la modules/plato/libplato.la modules/ray/libray.la modules/roto/libroto.la modules/rtv/librtv.la modules/snow/libsnow.la modules/sparkler/libsparkler.la modules/spiro/libspiro.la modules/stars/libstars.la modules/submit/libsubmit.la modules/swab/libswab.la modules/swarm/libswarm.la libs/grid/libgrid.la libs/puddle/libpuddle.la libs/ray/libray.la libs/sig/libsig.la libs/txt/libtxt.la libs/ascii/libascii.la libs/din/libdin.la + bin_PROGRAMS = rototiller -rototiller_SOURCES = fb.c fb.h fps.c fps.h knobs.h rototiller.c rototiller.h sdl_fb.c settings.h settings.c setup.h setup.c threads.c threads.h util.c util.h +rototiller_SOURCES = fb.c fb.h fps.c fps.h knobs.h main.c rototiller.h sdl_fb.c settings.h settings.c setup.h setup.c threads.c threads.h util.c util.h if ENABLE_DRM rototiller_SOURCES += drm_fb.c endif -rototiller_LDADD = modules/compose/libcompose.a modules/drizzle/libdrizzle.a modules/flui2d/libflui2d.a modules/julia/libjulia.a modules/meta2d/libmeta2d.a modules/montage/libmontage.a modules/pixbounce/libpixbounce.a modules/plasma/libplasma.a modules/plato/libplato.a modules/ray/libray.a modules/roto/libroto.a modules/rtv/librtv.a modules/snow/libsnow.a modules/sparkler/libsparkler.a modules/spiro/libspiro.a modules/stars/libstars.a modules/submit/libsubmit.a modules/swab/libswab.a modules/swarm/libswarm.a libs/grid/libgrid.a libs/puddle/libpuddle.a libs/ray/libray.a libs/sig/libsig.a libs/txt/libtxt.a libs/ascii/libascii.a libs/din/libdin.a -lm +rototiller_LDADD = librototiller.la -lm +#rototiller_LDADD = modules/compose/libcompose.a modules/drizzle/libdrizzle.a modules/flui2d/libflui2d.a modules/julia/libjulia.a modules/meta2d/libmeta2d.a modules/montage/libmontage.a modules/pixbounce/libpixbounce.a modules/plasma/libplasma.a modules/plato/libplato.a modules/ray/libray.a modules/roto/libroto.a modules/rtv/librtv.a modules/snow/libsnow.a modules/sparkler/libsparkler.a modules/spiro/libspiro.a modules/stars/libstars.a modules/submit/libsubmit.a modules/swab/libswab.a modules/swarm/libswarm.a libs/grid/libgrid.a libs/puddle/libpuddle.a libs/ray/libray.a libs/sig/libsig.a libs/txt/libtxt.a libs/ascii/libascii.a libs/din/libdin.a -lm diff --git a/src/libs/ascii/Makefile.am b/src/libs/ascii/Makefile.am index 41476bb..bc8ab4a 100644 --- a/src/libs/ascii/Makefile.am +++ b/src/libs/ascii/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libascii.a -libascii_a_SOURCES = ascii.c ascii.h -libascii_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libascii.la +libascii_la_SOURCES = ascii.c ascii.h +libascii_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/libs/din/Makefile.am b/src/libs/din/Makefile.am index b918de6..dfbf9bf 100644 --- a/src/libs/din/Makefile.am +++ b/src/libs/din/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libdin.a -libdin_a_SOURCES = din.c din.h v3f.h -libdin_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libdin.la +libdin_la_SOURCES = din.c din.h v3f.h +libdin_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/libs/grid/Makefile.am b/src/libs/grid/Makefile.am index e9c8f3a..2d93699 100644 --- a/src/libs/grid/Makefile.am +++ b/src/libs/grid/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libgrid.a -libgrid_a_SOURCES = grid.c grid.h macros.h -libgrid_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libgrid.la +libgrid_la_SOURCES = grid.c grid.h macros.h +libgrid_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/libs/puddle/Makefile.am b/src/libs/puddle/Makefile.am index faacb49..b3cc0f8 100644 --- a/src/libs/puddle/Makefile.am +++ b/src/libs/puddle/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libpuddle.a -libpuddle_a_SOURCES = puddle.c puddle.h -libpuddle_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libpuddle.la +libpuddle_la_SOURCES = puddle.c puddle.h +libpuddle_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/libs/ray/Makefile.am b/src/libs/ray/Makefile.am index f055d94..6439f63 100644 --- a/src/libs/ray/Makefile.am +++ b/src/libs/ray/Makefile.am @@ -1,4 +1,4 @@ -noinst_LIBRARIES = libray.a -libray_a_SOURCES = ray_3f.h ray_camera.c ray_camera.h ray_color.h ray_euler.c ray_euler.h ray_gamma.c ray_gamma.h ray_light_emitter.h ray_object.h ray_object_light.h ray_object_plane.h ray_object_point.h ray_object_sphere.h ray_object_type.h ray_ray.h ray_render.c ray_render.h ray_render_object.h ray_render_object_plane.h ray_render_object_point.h ray_render_object_sphere.h ray_scene.h ray_surface.h -libray_a_CFLAGS = -ffast-math -libray_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libray.la +libray_la_SOURCES = ray_3f.h ray_camera.c ray_camera.h ray_color.h ray_euler.c ray_euler.h ray_gamma.c ray_gamma.h ray_light_emitter.h ray_object.h ray_object_light.h ray_object_plane.h ray_object_point.h ray_object_sphere.h ray_object_type.h ray_ray.h ray_render.c ray_render.h ray_render_object.h ray_render_object_plane.h ray_render_object_point.h ray_render_object_sphere.h ray_scene.h ray_surface.h +libray_la_CFLAGS = -ffast-math +libray_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/libs/sig/Makefile.am b/src/libs/sig/Makefile.am index 7e2537c..d81ae95 100644 --- a/src/libs/sig/Makefile.am +++ b/src/libs/sig/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libsig.a -libsig_a_SOURCES = ops_abs.c ops_add.c ops_ceil.c ops_clamp.c ops_const.c ops_div.c ops_expand.c ops_floor.c ops_inv.c ops_lerp.c ops_max.c ops_min.c ops_mult.c ops_neg.c ops_pow.c ops_rand.c ops_round.c ops_scale.c ops_sin.c ops_sub.c sig.c sig.h -libsig_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libsig.la +libsig_la_SOURCES = ops_abs.c ops_add.c ops_ceil.c ops_clamp.c ops_const.c ops_div.c ops_expand.c ops_floor.c ops_inv.c ops_lerp.c ops_max.c ops_min.c ops_mult.c ops_neg.c ops_pow.c ops_rand.c ops_round.c ops_scale.c ops_sin.c ops_sub.c sig.c sig.h +libsig_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/libs/txt/Makefile.am b/src/libs/txt/Makefile.am index 88aa79b..0d0db46 100644 --- a/src/libs/txt/Makefile.am +++ b/src/libs/txt/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libtxt.a -libtxt_a_SOURCES = txt.c txt.h -libtxt_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs +noinst_LTLIBRARIES = libtxt.la +libtxt_la_SOURCES = txt.c txt.h +libtxt_la_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..5180529 --- /dev/null +++ b/src/main.c @@ -0,0 +1,340 @@ +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <inttypes.h> +#include <pthread.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <sys/time.h> +#include <unistd.h> + +#include "settings.h" +#include "setup.h" +#include "fb.h" +#include "fps.h" +#include "rototiller.h" +#include "util.h" + +/* Copyright (C) 2016 Vito Caputo <vcaputo@pengaru.com> */ + +#define NUM_FB_PAGES 3 +/* ^ By triple-buffering, we can have a page tied up being displayed, another + * tied up submitted and waiting for vsync, and still not block on getting + * another page so we can begin rendering another frame before vsync. With + * just two pages we end up twiddling thumbs until the vsync arrives. + */ +#define DEFAULT_VIDEO "sdl" + +extern fb_ops_t drm_fb_ops; +extern fb_ops_t sdl_fb_ops; +fb_ops_t *fb_ops; + +typedef struct rototiller_t { + const rototiller_module_t *module; + void *module_context; + pthread_t thread; + fb_t *fb; + struct timeval start_tv; + unsigned ticks_offset; +} rototiller_t; + +static rototiller_t rototiller; + + +typedef struct argv_t { + const char *module; + const char *video; + + unsigned use_defaults:1; + unsigned help:1; +} argv_t; + +/* + * ./rototiller --video=drm,dev=/dev/dri/card3,connector=VGA-1,mode=640x480@60 + * ./rototiller --video=sdl,size=640x480 + * ./rototiller --module=roto,foo=bar,module=settings + * ./rototiller --defaults + */ +static int parse_argv(int argc, const char *argv[], argv_t *res_args) +{ + int i; + + assert(argc > 0); + assert(argv); + assert(res_args); + + /* this is intentionally being kept very simple, no new dependencies like getopt. */ + + for (i = 1; i < argc; i++) { + if (!strncmp("--video=", argv[i], 8)) { + res_args->video = &argv[i][8]; + } else if (!strncmp("--module=", argv[i], 9)) { + res_args->module = &argv[i][9]; + } else if (!strcmp("--defaults", argv[i])) { + res_args->use_defaults = 1; + } else if (!strcmp("--help", argv[i])) { + res_args->help = 1; + } else { + return -EINVAL; + } + } + + return 0; +} + + +typedef struct setup_t { + settings_t *module; + settings_t *video; +} setup_t; + +/* FIXME: this is unnecessarily copy-pasta, i think modules should just be made + * more generic to encompass the setting up uniformly, then basically + * subclass the video backend vs. renderer stuff. + */ + +/* select video backend if not yet selected, then setup the selected backend. */ +static int setup_video(settings_t *settings, setting_desc_t **next_setting) +{ + const char *video; + + /* XXX: there's only one option currently, so this is simple */ + video = settings_get_key(settings, 0); + if (!video) { + setting_desc_t *desc; + const char *values[] = { +#ifdef HAVE_DRM + "drm", +#endif + "sdl", + NULL, + }; + int r; + + r = setting_desc_clone(&(setting_desc_t){ + .name = "Video Backend", + .key = NULL, + .regex = "[a-z]+", + .preferred = DEFAULT_VIDEO, + .values = values, + .annotations = NULL + }, next_setting); + if (r < 0) + return r; + + return 1; + } + + /* XXX: this is kind of hacky for now */ +#ifdef HAVE_DRM + if (!strcmp(video, "drm")) { + fb_ops = &drm_fb_ops; + + return drm_fb_ops.setup(settings, next_setting); + } else +#endif + if (!strcmp(video, "sdl")) { + fb_ops = &sdl_fb_ops; + + return sdl_fb_ops.setup(settings, next_setting); + } + + return -EINVAL; +} + + +/* turn args into settings, automatically applying defaults if appropriate, or interactively if appropriate. */ +/* returns negative value on error, 0 when settings unchanged from args, 1 when changed */ +static int setup_from_args(argv_t *args, setup_t *res_setup) +{ + int r, changes = 0; + setup_t setup; + + setup.module = settings_new(args->module); + if (!setup.module) + return -ENOMEM; + + setup.video = settings_new(args->video); + if (!setup.video) { + settings_free(setup.module); + + return -ENOMEM; + } + + r = setup_interactively(setup.module, rototiller_module_setup, args->use_defaults); + if (r < 0) { + settings_free(setup.module); + settings_free(setup.video); + + return r; + } + + if (r) + changes = 1; + + r = setup_interactively(setup.video, setup_video, args->use_defaults); + if (r < 0) { + settings_free(setup.module); + settings_free(setup.video); + + return r; + } + + if (r) + changes = 1; + + *res_setup = setup; + + return changes; +} + + +static int print_setup_as_args(setup_t *setup) +{ + char *module_args, *video_args; + char buf[64]; + int r; + + module_args = settings_as_arg(setup->module); + if (!module_args) { + r = -ENOMEM; + + goto _out; + } + + video_args = settings_as_arg(setup->video); + if (!video_args) { + r = -ENOMEM; + + goto _out_module; + } + + r = printf("\nConfigured settings as flags:\n --module=%s --video=%s\n\nPress enter to continue...\n", + module_args, + video_args); + + if (r < 0) + goto _out_video; + + (void) fgets(buf, sizeof(buf), stdin); + +_out_video: + free(video_args); +_out_module: + free(module_args); +_out: + return r; +} + + +static int print_help(void) +{ + return printf( + "Run without any flags or partial settings for interactive mode.\n" + "\n" + "Supported flags:\n" + " --defaults use defaults for unspecified settings\n" + " --help this help\n" + " --module= module settings\n" + " --video= video settings\n" + ); +} + + +static unsigned get_ticks(const struct timeval *start, const struct timeval *now, unsigned offset) +{ + return (unsigned)((now->tv_sec - start->tv_sec) * 1000 + (now->tv_usec - start->tv_usec) / 1000) + offset; +} + + +static void * rototiller_thread(void *_rt) +{ + rototiller_t *rt = _rt; + struct timeval now; + + for (;;) { + fb_page_t *page; + unsigned ticks; + + page = fb_page_get(rt->fb); + + gettimeofday(&now, NULL); + ticks = get_ticks(&rt->start_tv, &now, rt->ticks_offset); + + rototiller_module_render(rt->module, rt->module_context, ticks, &page->fragment); + + fb_page_put(rt->fb, page); + } + + return NULL; +} + + +/* When run with partial/no arguments, if stdin is a tty, enter an interactive setup. + * If stdin is not a tty, or if --defaults is supplied in argv, default settings are used. + * If any changes to the settings occur in the course of execution, either interactively or + * throught --defaults, then print out the explicit CLI invocation usable for reproducing + * the invocation. + */ +int main(int argc, const char *argv[]) +{ + setup_t setup = {}; + argv_t args = {}; + int r; + + exit_if(parse_argv(argc, argv, &args) < 0, + "unable to process arguments"); + + if (args.help) + return print_help() < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + + exit_if((r = setup_from_args(&args, &setup)) < 0, + "unable to setup: %s", strerror(-r)); + + exit_if(r && print_setup_as_args(&setup) < 0, + "unable to print setup"); + + exit_if(!(rototiller.module = rototiller_lookup_module(settings_get_key(setup.module, 0))), + "unable to lookup module from settings \"%s\"", settings_get_key(setup.module, 0)); + + exit_if((r = fb_new(fb_ops, setup.video, NUM_FB_PAGES, &rototiller.fb)) < 0, + "unable to create fb: %s", strerror(-r)); + + exit_if(!fps_setup(), + "unable to setup fps counter"); + + exit_if((r = rototiller_init()) < 0, + "unable to initialize librototiller: %s", strerror(-r)); + + gettimeofday(&rototiller.start_tv, NULL); + exit_if((r = rototiller_module_create_context( + rototiller.module, + get_ticks(&rototiller.start_tv, + &rototiller.start_tv, + rototiller.ticks_offset), + &rototiller.module_context)) < 0, + "unable to create module context: %s", strerror(-r)); + + pexit_if(pthread_create(&rototiller.thread, NULL, rototiller_thread, &rototiller) != 0, + "unable to create dispatch thread"); + + for (;;) { + if (fb_flip(rototiller.fb) < 0) + break; + + fps_print(rototiller.fb); + } + + pthread_cancel(rototiller.thread); + pthread_join(rototiller.thread, NULL); + rototiller_shutdown(); + + if (rototiller.module_context) + rototiller.module->destroy_context(rototiller.module_context); + + fb_free(rototiller.fb); + + return EXIT_SUCCESS; +} diff --git a/src/modules/compose/Makefile.am b/src/modules/compose/Makefile.am index 926db7e..e77bf69 100644 --- a/src/modules/compose/Makefile.am +++ b/src/modules/compose/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libcompose.a -libcompose_a_SOURCES = compose.c -libcompose_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs +noinst_LTLIBRARIES = libcompose.la +libcompose_la_SOURCES = compose.c +libcompose_la_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/modules/drizzle/Makefile.am b/src/modules/drizzle/Makefile.am index caaa45f..a6bb00b 100644 --- a/src/modules/drizzle/Makefile.am +++ b/src/modules/drizzle/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libdrizzle.a -libdrizzle_a_SOURCES = drizzle.c -libdrizzle_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs +noinst_LTLIBRARIES = libdrizzle.la +libdrizzle_la_SOURCES = drizzle.c +libdrizzle_la_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/modules/flui2d/Makefile.am b/src/modules/flui2d/Makefile.am index 239de9e..90fc109 100644 --- a/src/modules/flui2d/Makefile.am +++ b/src/modules/flui2d/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libflui2d.a -libflui2d_a_SOURCES = flui2d.c -libflui2d_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libflui2d.la +libflui2d_la_SOURCES = flui2d.c +libflui2d_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/modules/julia/Makefile.am b/src/modules/julia/Makefile.am index 8e94f14..a61bad8 100644 --- a/src/modules/julia/Makefile.am +++ b/src/modules/julia/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libjulia.a -libjulia_a_SOURCES = julia.c -libjulia_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libjulia.la +libjulia_la_SOURCES = julia.c +libjulia_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/modules/meta2d/Makefile.am b/src/modules/meta2d/Makefile.am index b1394d1..73b00f4 100644 --- a/src/modules/meta2d/Makefile.am +++ b/src/modules/meta2d/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libmeta2d.a -libmeta2d_a_SOURCES = meta2d.c v2f.h v3f.h -libmeta2d_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs +noinst_LTLIBRARIES = libmeta2d.la +libmeta2d_la_SOURCES = meta2d.c v2f.h v3f.h +libmeta2d_la_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/modules/montage/Makefile.am b/src/modules/montage/Makefile.am index 7465510..0c2c376 100644 --- a/src/modules/montage/Makefile.am +++ b/src/modules/montage/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libmontage.a -libmontage_a_SOURCES = montage.c -libmontage_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs +noinst_LTLIBRARIES = libmontage.la +libmontage_la_SOURCES = montage.c +libmontage_la_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/modules/pixbounce/Makefile.am b/src/modules/pixbounce/Makefile.am index a55374a..6464dcb 100644 --- a/src/modules/pixbounce/Makefile.am +++ b/src/modules/pixbounce/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libpixbounce.a -libpixbounce_a_SOURCES = draw.h pixbounce.c -libpixbounce_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libpixbounce.la +libpixbounce_la_SOURCES = draw.h pixbounce.c +libpixbounce_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/modules/plasma/Makefile.am b/src/modules/plasma/Makefile.am index a856df1..edb3760 100644 --- a/src/modules/plasma/Makefile.am +++ b/src/modules/plasma/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libplasma.a -libplasma_a_SOURCES = plasma.c -libplasma_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libplasma.la +libplasma_la_SOURCES = plasma.c +libplasma_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/modules/plato/Makefile.am b/src/modules/plato/Makefile.am index d0b9069..b0550d8 100644 --- a/src/modules/plato/Makefile.am +++ b/src/modules/plato/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libplato.a -libplato_a_SOURCES = plato.c -libplato_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs +noinst_LTLIBRARIES = libplato.la +libplato_la_SOURCES = plato.c +libplato_la_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/modules/ray/Makefile.am b/src/modules/ray/Makefile.am index 637a921..f20850a 100644 --- a/src/modules/ray/Makefile.am +++ b/src/modules/ray/Makefile.am @@ -1,4 +1,4 @@ -noinst_LIBRARIES = libray.a -libray_a_SOURCES = ray.c -libray_a_CFLAGS = -ffast-math -libray_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs +noinst_LTLIBRARIES = libray.la +libray_la_SOURCES = ray.c +libray_la_CFLAGS = -ffast-math +libray_la_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/modules/roto/Makefile.am b/src/modules/roto/Makefile.am index 6682751..2b704c1 100644 --- a/src/modules/roto/Makefile.am +++ b/src/modules/roto/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libroto.a -libroto_a_SOURCES = roto.c -libroto_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libroto.la +libroto_la_SOURCES = roto.c +libroto_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/modules/rtv/Makefile.am b/src/modules/rtv/Makefile.am index 4d5cb6e..8a4f341 100644 --- a/src/modules/rtv/Makefile.am +++ b/src/modules/rtv/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = librtv.a -librtv_a_SOURCES = rtv.c -librtv_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs +noinst_LTLIBRARIES = librtv.la +librtv_la_SOURCES = rtv.c +librtv_la_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/modules/snow/Makefile.am b/src/modules/snow/Makefile.am index 73f767d..d4a602a 100644 --- a/src/modules/snow/Makefile.am +++ b/src/modules/snow/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libsnow.a -libsnow_a_SOURCES = snow.c -libsnow_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libsnow.la +libsnow_la_SOURCES = snow.c +libsnow_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/modules/sparkler/Makefile.am b/src/modules/sparkler/Makefile.am index 40a9bc8..f056aac 100644 --- a/src/modules/sparkler/Makefile.am +++ b/src/modules/sparkler/Makefile.am @@ -1,4 +1,4 @@ -noinst_LIBRARIES = libsparkler.a -libsparkler_a_SOURCES = bsp.c bsp.h burst.c chunker.c chunker.h container.h list.h particle.c particle.h particles.c particles.h rocket.c simple.c spark.c sparkler.c v3f.h xplode.c -libsparkler_a_CFLAGS = -ffast-math -libsparkler_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libsparkler.la +libsparkler_la_SOURCES = bsp.c bsp.h burst.c chunker.c chunker.h container.h list.h particle.c particle.h particles.c particles.h rocket.c simple.c spark.c sparkler.c v3f.h xplode.c +libsparkler_la_CFLAGS = -ffast-math +libsparkler_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/modules/spiro/Makefile.am b/src/modules/spiro/Makefile.am index f03d8cd..0f8a543 100644 --- a/src/modules/spiro/Makefile.am +++ b/src/modules/spiro/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libspiro.a -libspiro_a_SOURCES = draw.h spiro.c -libspiro_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libspiro.la +libspiro_la_SOURCES = draw.h spiro.c +libspiro_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/modules/stars/Makefile.am b/src/modules/stars/Makefile.am index 20ee80e..ebeb4dd 100644 --- a/src/modules/stars/Makefile.am +++ b/src/modules/stars/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libstars.a -libstars_a_SOURCES = draw.h stars.c -libstars_a_CPPFLAGS = -I@top_srcdir@/src +noinst_LTLIBRARIES = libstars.la +libstars_la_SOURCES = draw.h stars.c +libstars_la_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/modules/submit/Makefile.am b/src/modules/submit/Makefile.am index d8a02e4..23a2fda 100644 --- a/src/modules/submit/Makefile.am +++ b/src/modules/submit/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libsubmit.a -libsubmit_a_SOURCES = submit.c -libsubmit_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs +noinst_LTLIBRARIES = libsubmit.la +libsubmit_la_SOURCES = submit.c +libsubmit_la_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/modules/swab/Makefile.am b/src/modules/swab/Makefile.am index 4db914b..c99265a 100644 --- a/src/modules/swab/Makefile.am +++ b/src/modules/swab/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libswab.a -libswab_a_SOURCES = swab.c -libswab_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs +noinst_LTLIBRARIES = libswab.la +libswab_la_SOURCES = swab.c +libswab_la_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/modules/swarm/Makefile.am b/src/modules/swarm/Makefile.am index 327aee8..555bd8e 100644 --- a/src/modules/swarm/Makefile.am +++ b/src/modules/swarm/Makefile.am @@ -1,3 +1,3 @@ -noinst_LIBRARIES = libswarm.a -libswarm_a_SOURCES = swarm.c -libswarm_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs +noinst_LTLIBRARIES = libswarm.la +libswarm_la_SOURCES = swarm.c +libswarm_la_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs diff --git a/src/rototiller.c b/src/rototiller.c index 84898da..18f0376 100644 --- a/src/rototiller.c +++ b/src/rototiller.c @@ -11,27 +11,16 @@ #include <unistd.h> #include "settings.h" -#include "setup.h" #include "fb.h" -#include "fps.h" #include "rototiller.h" #include "threads.h" #include "util.h" /* Copyright (C) 2016 Vito Caputo <vcaputo@pengaru.com> */ -#define NUM_FB_PAGES 3 -/* ^ By triple-buffering, we can have a page tied up being displayed, another - * tied up submitted and waiting for vsync, and still not block on getting - * another page so we can begin rendering another frame before vsync. With - * just two pages we end up twiddling thumbs until the vsync arrives. - */ #define DEFAULT_MODULE "rtv" -#define DEFAULT_VIDEO "sdl" -extern fb_ops_t drm_fb_ops; -extern fb_ops_t sdl_fb_ops; -fb_ops_t *fb_ops; +static threads_t *rototiller_threads; extern rototiller_module_t compose_module; extern rototiller_module_t drizzle_module; @@ -75,17 +64,21 @@ static const rototiller_module_t *modules[] = { &swarm_module, }; -typedef struct rototiller_t { - const rototiller_module_t *module; - void *module_context; - threads_t *threads; - pthread_t thread; - fb_t *fb; - struct timeval start_tv; - unsigned ticks_offset; -} rototiller_t; -static rototiller_t rototiller; +/* initialize rototiller (create rendering threads) */ +int rototiller_init(void) +{ + if (!(rototiller_threads = threads_create())) + return -errno; + + return 0; +} + + +void rototiller_shutdown(void) +{ + threads_destroy(rototiller_threads); +} const rototiller_module_t * rototiller_lookup_module(const char *name) @@ -113,6 +106,10 @@ void rototiller_get_modules(const rototiller_module_t ***res_modules, size_t *re static void module_render_fragment(const rototiller_module_t *module, void *context, threads_t *threads, unsigned ticks, fb_fragment_t *fragment) { + assert(module); + assert(threads); + assert(fragment); + if (module->prepare_frame) { rototiller_fragmenter_t fragmenter; @@ -136,114 +133,31 @@ static void module_render_fragment(const rototiller_module_t *module, void *cont */ void rototiller_module_render(const rototiller_module_t *module, void *context, unsigned ticks, fb_fragment_t *fragment) { - module_render_fragment(module, context, rototiller.threads, ticks, fragment); + module_render_fragment(module, context, rototiller_threads, ticks, fragment); } - -typedef struct argv_t { - const char *module; - const char *video; - - unsigned use_defaults:1; - unsigned help:1; -} argv_t; - -/* - * ./rototiller --video=drm,dev=/dev/dri/card3,connector=VGA-1,mode=640x480@60 - * ./rototiller --video=sdl,size=640x480 - * ./rototiller --module=roto,foo=bar,module=settings - * ./rototiller --defaults - */ -static int parse_argv(int argc, const char *argv[], argv_t *res_args) +int rototiller_module_create_context(const rototiller_module_t *module, unsigned ticks, void **res_context) { - int i; - - assert(argc > 0); - assert(argv); - assert(res_args); - - /* this is intentionally being kept very simple, no new dependencies like getopt. */ - - for (i = 1; i < argc; i++) { - if (!strncmp("--video=", argv[i], 8)) { - res_args->video = &argv[i][8]; - } else if (!strncmp("--module=", argv[i], 9)) { - res_args->module = &argv[i][9]; - } else if (!strcmp("--defaults", argv[i])) { - res_args->use_defaults = 1; - } else if (!strcmp("--help", argv[i])) { - res_args->help = 1; - } else { - return -EINVAL; - } - } - - return 0; -} - + void *context; -typedef struct setup_t { - settings_t *module; - settings_t *video; -} setup_t; + assert(module); + assert(res_context); -/* FIXME: this is unnecessarily copy-pasta, i think modules should just be made - * more generic to encompass the setting up uniformly, then basically - * subclass the video backend vs. renderer stuff. - */ + if (!module->create_context) + return 0; -/* select video backend if not yet selected, then setup the selected backend. */ -static int setup_video(settings_t *settings, setting_desc_t **next_setting) -{ - const char *video; - - /* XXX: there's only one option currently, so this is simple */ - video = settings_get_key(settings, 0); - if (!video) { - setting_desc_t *desc; - const char *values[] = { -#ifdef HAVE_DRM - "drm", -#endif - "sdl", - NULL, - }; - int r; - - r = setting_desc_clone(&(setting_desc_t){ - .name = "Video Backend", - .key = NULL, - .regex = "[a-z]+", - .preferred = DEFAULT_VIDEO, - .values = values, - .annotations = NULL - }, next_setting); - if (r < 0) - return r; - - return 1; - } - - /* XXX: this is kind of hacky for now */ -#ifdef HAVE_DRM - if (!strcmp(video, "drm")) { - fb_ops = &drm_fb_ops; - - return drm_fb_ops.setup(settings, next_setting); - } else -#endif - if (!strcmp(video, "sdl")) { - fb_ops = &sdl_fb_ops; + context = module->create_context(ticks, threads_num_threads(rototiller_threads)); + if (!context) + return -ENOMEM; - return sdl_fb_ops.setup(settings, next_setting); - } + *res_context = context; - return -EINVAL; + return 0; } /* select module if not yet selected, then setup the module. */ -static int setup_module(settings_t *settings, setting_desc_t **next_setting) +int rototiller_module_setup(settings_t *settings, setting_desc_t **next_setting) { const rototiller_module_t *module; const char *name; @@ -284,198 +198,3 @@ static int setup_module(settings_t *settings, setting_desc_t **next_setting) return 0; } - - -/* turn args into settings, automatically applying defaults if appropriate, or interactively if appropriate. */ -/* returns negative value on error, 0 when settings unchanged from args, 1 when changed */ -static int setup_from_args(argv_t *args, setup_t *res_setup) -{ - int r, changes = 0; - setup_t setup; - - setup.module = settings_new(args->module); - if (!setup.module) - return -ENOMEM; - - setup.video = settings_new(args->video); - if (!setup.video) { - settings_free(setup.module); - - return -ENOMEM; - } - - r = setup_interactively(setup.module, setup_module, args->use_defaults); - if (r < 0) { - settings_free(setup.module); - settings_free(setup.video); - - return r; - } - - if (r) - changes = 1; - - r = setup_interactively(setup.video, setup_video, args->use_defaults); - if (r < 0) { - settings_free(setup.module); - settings_free(setup.video); - - return r; - } - - if (r) - changes = 1; - - *res_setup = setup; - - return changes; -} - - -static int print_setup_as_args(setup_t *setup) -{ - char *module_args, *video_args; - char buf[64]; - int r; - - module_args = settings_as_arg(setup->module); - if (!module_args) { - r = -ENOMEM; - - goto _out; - } - - video_args = settings_as_arg(setup->video); - if (!video_args) { - r = -ENOMEM; - - goto _out_module; - } - - r = printf("\nConfigured settings as flags:\n --module=%s --video=%s\n\nPress enter to continue...\n", - module_args, - video_args); - - if (r < 0) - goto _out_video; - - (void) fgets(buf, sizeof(buf), stdin); - -_out_video: - free(video_args); -_out_module: - free(module_args); -_out: - return r; -} - - -static int print_help(void) -{ - return printf( - "Run without any flags or partial settings for interactive mode.\n" - "\n" - "Supported flags:\n" - " --defaults use defaults for unspecified settings\n" - " --help this help\n" - " --module= module settings\n" - " --video= video settings\n" - ); -} - - -static unsigned get_ticks(const struct timeval *start, const struct timeval *now, unsigned offset) -{ - return (unsigned)((now->tv_sec - start->tv_sec) * 1000 + (now->tv_usec - start->tv_usec) / 1000) + offset; -} - - -static void * rototiller_thread(void *_rt) -{ - rototiller_t *rt = _rt; - struct timeval now; - - for (;;) { - fb_page_t *page; - unsigned ticks; - - page = fb_page_get(rt->fb); - - gettimeofday(&now, NULL); - ticks = get_ticks(&rt->start_tv, &now, rt->ticks_offset); - - module_render_fragment(rt->module, rt->module_context, rt->threads, ticks, &page->fragment); - - fb_page_put(rt->fb, page); - } - - return NULL; -} - - -/* When run with partial/no arguments, if stdin is a tty, enter an interactive setup. - * If stdin is not a tty, or if --defaults is supplied in argv, default settings are used. - * If any changes to the settings occur in the course of execution, either interactively or - * throught --defaults, then print out the explicit CLI invocation usable for reproducing - * the invocation. - */ -int main(int argc, const char *argv[]) -{ - setup_t setup = {}; - argv_t args = {}; - int r; - - exit_if(parse_argv(argc, argv, &args) < 0, - "unable to process arguments"); - - if (args.help) - return print_help() < 0 ? EXIT_FAILURE : EXIT_SUCCESS; - - exit_if((r = setup_from_args(&args, &setup)) < 0, - "unable to setup: %s", strerror(-r)); - - exit_if(r && print_setup_as_args(&setup) < 0, - "unable to print setup"); - - exit_if(!(rototiller.module = rototiller_lookup_module(settings_get_key(setup.module, 0))), - "unable to lookup module from settings \"%s\"", settings_get_key(setup.module, 0)); - - exit_if((r = fb_new(fb_ops, setup.video, NUM_FB_PAGES, &rototiller.fb)) < 0, - "unable to create fb: %s", strerror(-r)); - - exit_if(!fps_setup(), - "unable to setup fps counter"); - - pexit_if(!(rototiller.threads = threads_create()), - "unable to create rendering threads"); - - gettimeofday(&rototiller.start_tv, NULL); - exit_if(rototiller.module->create_context && - !(rototiller.module_context = rototiller.module->create_context( - get_ticks(&rototiller.start_tv, - &rototiller.start_tv, - rototiller.ticks_offset), - threads_num_threads(rototiller.threads))), - "unable to create module context"); - - pexit_if(pthread_create(&rototiller.thread, NULL, rototiller_thread, &rototiller) != 0, - "unable to create dispatch thread"); - - for (;;) { - if (fb_flip(rototiller.fb) < 0) - break; - - fps_print(rototiller.fb); - } - - pthread_cancel(rototiller.thread); - pthread_join(rototiller.thread, NULL); - threads_destroy(rototiller.threads); - - if (rototiller.module_context) - rototiller.module->destroy_context(rototiller.module_context); - - fb_free(rototiller.fb); - - return EXIT_SUCCESS; -} diff --git a/src/rototiller.h b/src/rototiller.h index e185624..fde7d43 100644 --- a/src/rototiller.h +++ b/src/rototiller.h @@ -25,8 +25,12 @@ typedef struct rototiller_module_t { char *license; } rototiller_module_t; +int rototiller_init(void); +void rototiller_shutdown(void); const rototiller_module_t * rototiller_lookup_module(const char *name); void rototiller_get_modules(const rototiller_module_t ***res_modules, size_t *res_n_modules); void rototiller_module_render(const rototiller_module_t *module, void *context, unsigned ticks, fb_fragment_t *fragment); +int rototiller_module_create_context(const rototiller_module_t *module, unsigned ticks, void **res_context); +int rototiller_module_setup(settings_t *settings, setting_desc_t **next_setting); #endif |