From b686b405c6a22b26e9b8082c92ed91513608bea3 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Fri, 1 Oct 2021 16:35:08 -0700 Subject: *: librototiller->libtil Largely mechanical rename of librototiller -> libtil, but introducing a til_ prefix to all librototiller (now libtil) functions and types where a rototiller prefix was absent. This is just a step towards a more libized librototiller, and til is just a nicer to type/read prefix than rototiller_. --- src/Makefile.am | 13 +- src/drm_fb.c | 46 ++-- src/fb.c | 442 -------------------------------------- src/fb.h | 108 ---------- src/fps.c | 8 +- src/fps.h | 4 +- src/knobs.h | 91 -------- src/libs/ray/ray_camera.c | 4 +- src/libs/ray/ray_camera.h | 6 +- src/libs/ray/ray_render.c | 4 +- src/libs/ray/ray_render.h | 4 +- src/libs/txt/txt.c | 8 +- src/libs/txt/txt.h | 4 +- src/main.c | 97 ++++----- src/modules/compose/compose.c | 47 ++-- src/modules/drizzle/drizzle.c | 25 +-- src/modules/flui2d/flui2d.c | 32 +-- src/modules/julia/julia.c | 14 +- src/modules/meta2d/meta2d.c | 17 +- src/modules/montage/montage.c | 53 +++-- src/modules/pixbounce/pixbounce.c | 10 +- src/modules/plasma/plasma.c | 14 +- src/modules/plato/plato.c | 18 +- src/modules/ray/ray.c | 18 +- src/modules/roto/roto.c | 14 +- src/modules/rtv/rtv.c | 131 +++++------ src/modules/snow/snow.c | 16 +- src/modules/sparkler/burst.c | 16 +- src/modules/sparkler/helpers.h | 7 +- src/modules/sparkler/particle.h | 11 +- src/modules/sparkler/particles.c | 26 +-- src/modules/sparkler/particles.h | 9 +- src/modules/sparkler/rocket.c | 9 +- src/modules/sparkler/simple.c | 9 +- src/modules/sparkler/spark.c | 9 +- src/modules/sparkler/sparkler.c | 38 ++-- src/modules/sparkler/xplode.c | 9 +- src/modules/spiro/spiro.c | 23 +- src/modules/stars/stars.c | 25 +-- src/modules/submit/submit.c | 32 +-- src/modules/swab/swab.c | 20 +- src/modules/swarm/swarm.c | 12 +- src/rototiller.c | 207 ------------------ src/rototiller.h | 37 ---- src/sdl_fb.c | 90 ++++---- src/settings.c | 391 --------------------------------- src/settings.h | 43 ---- src/setup.c | 20 +- src/setup.h | 4 +- src/threads.c | 168 --------------- src/threads.h | 15 -- src/til.c | 207 ++++++++++++++++++ src/til.h | 37 ++++ src/til_fb.c | 442 ++++++++++++++++++++++++++++++++++++++ src/til_fb.h | 108 ++++++++++ src/til_knobs.h | 91 ++++++++ src/til_settings.c | 388 +++++++++++++++++++++++++++++++++ src/til_settings.h | 43 ++++ src/til_threads.c | 166 ++++++++++++++ src/til_threads.h | 14 ++ src/til_util.c | 35 +++ src/til_util.h | 32 +++ src/util.c | 35 --- src/util.h | 32 --- 64 files changed, 2057 insertions(+), 2051 deletions(-) delete mode 100644 src/fb.c delete mode 100644 src/fb.h delete mode 100644 src/knobs.h delete mode 100644 src/rototiller.c delete mode 100644 src/rototiller.h delete mode 100644 src/settings.c delete mode 100644 src/settings.h delete mode 100644 src/threads.c delete mode 100644 src/threads.h create mode 100644 src/til.c create mode 100644 src/til.h create mode 100644 src/til_fb.c create mode 100644 src/til_fb.h create mode 100644 src/til_knobs.h create mode 100644 src/til_settings.c create mode 100644 src/til_settings.h create mode 100644 src/til_threads.c create mode 100644 src/til_threads.h create mode 100644 src/til_util.c create mode 100644 src/til_util.h delete mode 100644 src/util.c delete mode 100644 src/util.h diff --git a/src/Makefile.am b/src/Makefile.am index c2e8653..c0a20b5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,14 +1,13 @@ 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 +noinst_LTLIBRARIES = libtil.la +libtil_la_SOURCES = til_fb.c til_fb.h til_knobs.h til.c til.h til_settings.h til_settings.c til_threads.c til_threads.h til_util.c til_util.h +libtil_la_CPPFLAGS = -I@top_srcdir@/src +libtil_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 main.c rototiller.h sdl_fb.c settings.h settings.c setup.h setup.c threads.c threads.h util.c util.h +rototiller_SOURCES = fps.c fps.h main.c sdl_fb.c setup.h setup.c til.h til_fb.c til_fb.h til_knobs.h til_settings.c til_settings.h til_threads.c til_threads.h til_util.c til_util.h if ENABLE_DRM rototiller_SOURCES += drm_fb.c endif -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 +rototiller_LDADD = libtil.la -lm diff --git a/src/drm_fb.c b/src/drm_fb.c index 9d70b91..3bd7d0d 100644 --- a/src/drm_fb.c +++ b/src/drm_fb.c @@ -12,9 +12,9 @@ #include #include -#include "fb.h" -#include "settings.h" -#include "util.h" +#include "til_fb.h" +#include "til_settings.h" +#include "til_util.h" /* drm fb backend, everything drm-specific in rototiller resides here. */ @@ -68,9 +68,9 @@ static const char * connector_type_name(uint32_t type) { } -static int dev_desc_generator(void *setup_context, setting_desc_t **res_desc) +static int dev_desc_generator(void *setup_context, til_setting_desc_t **res_desc) { - return setting_desc_clone(&(setting_desc_t){ + return til_setting_desc_clone(&(til_setting_desc_t){ .name = "DRM Device Path", .key = "dev", .regex = "/dev/dri/card[0-9]", @@ -145,7 +145,7 @@ static void free_strv(const char **strv) } -static int connector_desc_generator(void *setup_context, setting_desc_t **res_desc) +static int connector_desc_generator(void *setup_context, til_setting_desc_t **res_desc) { drm_fb_setup_t *s = setup_context; const char **connectors; @@ -157,7 +157,7 @@ static int connector_desc_generator(void *setup_context, setting_desc_t **res_de if (r < 0) return r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "DRM Connector", .key = "connector", .regex = "[a-zA-Z0-9]+", @@ -254,7 +254,7 @@ _out: } -static int mode_desc_generator(void *setup_context, setting_desc_t **res_desc) +static int mode_desc_generator(void *setup_context, til_setting_desc_t **res_desc) { drm_fb_setup_t *s = setup_context; const char **modes; @@ -266,7 +266,7 @@ static int mode_desc_generator(void *setup_context, setting_desc_t **res_desc) if (r < 0) return r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "DRM Video Mode", .key = "mode", .regex = "[0-9]+[xX][0-9]+@[0-9]+", @@ -283,10 +283,10 @@ static int mode_desc_generator(void *setup_context, setting_desc_t **res_desc) /* setup is called repeatedly as settings is constructed, until 0 is returned. */ /* a negative value is returned on error */ /* positive value indicates another setting is needed, described in next_setting */ -static int drm_fb_setup(const settings_t *settings, setting_desc_t **next_setting) +static int drm_fb_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) { drm_fb_setup_t context = {}; - setting_desc_generator_t generators[] = { + til_setting_desc_generator_t generators[] = { { .key = "dev", .value_ptr = &context.dev, @@ -305,7 +305,7 @@ static int drm_fb_setup(const settings_t *settings, setting_desc_t **next_settin if (!drmAvailable()) return -ENOSYS; - return settings_apply_desc_generators(settings, generators, nelems(generators), &context, next_setting); + return til_settings_apply_desc_generators(settings, generators, nelems(generators), &context, next_setting); } @@ -335,7 +335,7 @@ static drmModeModeInfo * lookup_mode(drmModeConnector *connector, const char *mo /* prepare the drm context for use with the supplied settings */ -static int drm_fb_init(const settings_t *settings, void **res_context) +static int drm_fb_init(const til_settings_t *settings, void **res_context) { drm_fb_t *c; const char *dev; @@ -351,19 +351,19 @@ static int drm_fb_init(const settings_t *settings, void **res_context) goto _err; } - dev = settings_get_value(settings, "dev"); + dev = til_settings_get_value(settings, "dev"); if (!dev) { r = -EINVAL; goto _err; } - connector = settings_get_value(settings, "connector"); + connector = til_settings_get_value(settings, "connector"); if (!connector) { r = -EINVAL; goto _err; } - mode = settings_get_value(settings, "mode"); + mode = til_settings_get_value(settings, "mode"); if (!mode) { r = -EINVAL; goto _err; @@ -422,7 +422,7 @@ _err: } -static void drm_fb_shutdown(fb_t *fb, void *context) +static void drm_fb_shutdown(til_fb_t *fb, void *context) { drm_fb_t *c = context; @@ -435,7 +435,7 @@ static void drm_fb_shutdown(fb_t *fb, void *context) } -static int drm_fb_acquire(fb_t *fb, void *context, void *page) +static int drm_fb_acquire(til_fb_t *fb, void *context, void *page) { drm_fb_t *c = context; drm_fb_page_t *p = page; @@ -444,13 +444,13 @@ static int drm_fb_acquire(fb_t *fb, void *context, void *page) } -static void drm_fb_release(fb_t *fb, void *context) +static void drm_fb_release(til_fb_t *fb, void *context) { /* TODO restore the existing mode @ last acquire? */ } -static void * drm_fb_page_alloc(fb_t *fb, void *context, fb_page_t *res_page) +static void * drm_fb_page_alloc(til_fb_t *fb, void *context, til_fb_page_t *res_page) { struct drm_mode_create_dumb create_dumb = { .bpp = 32 }; struct drm_mode_map_dumb map_dumb = {}; @@ -493,7 +493,7 @@ static void * drm_fb_page_alloc(fb_t *fb, void *context, fb_page_t *res_page) } -static int drm_fb_page_free(fb_t *fb, void *context, void *page) +static int drm_fb_page_free(til_fb_t *fb, void *context, void *page) { struct drm_mode_destroy_dumb destroy_dumb = {}; drm_fb_t *c = context; @@ -511,7 +511,7 @@ static int drm_fb_page_free(fb_t *fb, void *context, void *page) } -static int drm_fb_page_flip(fb_t *fb, void *context, void *page) +static int drm_fb_page_flip(til_fb_t *fb, void *context, void *page) { drmEventContext drm_ev_ctx = { .version = DRM_EVENT_CONTEXT_VERSION, @@ -528,7 +528,7 @@ static int drm_fb_page_flip(fb_t *fb, void *context, void *page) } -fb_ops_t drm_fb_ops = { +til_fb_ops_t drm_fb_ops = { .setup = drm_fb_setup, .init = drm_fb_init, .shutdown = drm_fb_shutdown, diff --git a/src/fb.c b/src/fb.c deleted file mode 100644 index 1c94bdf..0000000 --- a/src/fb.c +++ /dev/null @@ -1,442 +0,0 @@ -#include -#include -#include -#include -#include - -#include "fb.h" -#include "settings.h" -#include "util.h" - -/* Copyright (C) 2016-2017 Vito Caputo */ - - -/* I've used a separate thread for page-flipping duties because the libdrm api - * (and related kernel ioctl) for page flips doesn't appear to support queueing - * multiple flip requests. In this use case we aren't interactive and wish to - * just accumulate rendered pages until we run out of spare pages, allowing the - * renderer to get as far ahead of vsync as possible, and certainly never - * blocked waiting for vsync unless there's no spare page available for drawing - * into. - * - * In lieu of a queueing mechanism on the drm fd, we must submit the next page - * once the currently submitted page is flipped to - it's at that moment we - * won't get EBUSY from the ioctl any longer. Without a dedicated thread - * submitting flip requests and synchronously consuming their flip events, - * we're liable to introduce latency in the page flip submission if implemented - * in a more opportunistic manner whenever the fb api is entered from the - * render loop. - * - * If the kernel simply let us queue multiple flip requests we could maintain - * our submission queue entirely in the drm fd, and get available pages from - * the drm event handler once our pool of pages is depleted. The kernel on - * vsync could check the fd to see if another flip is queued and there would be - * the least latency possible in submitting the flips - the least likely to - * miss a vsync. This would also elide the need for synchronization in - * userspace between the renderer and the flipper thread, since there would no - * longer be a flipper thread. - * - * Let me know if you're aware of a better way with existing mainline drm! - * - * - * XXX: fb_new() used to create a thread which did the equivalent of fb_flip() - * continuously in a loop. This posed a problem for the sdl_fb backend, due to - * the need for event pumping in the page flip hook. SDL internally uses TLS - * and requires that the same thread which initialized SDL call the event - * functions. To satisfy this requirement, the body of the flipper thread loop - * has been moved to the fb_flip() function. Rototiller's main thread is - * expected to call this repeatedly, turning it effectively into the flipper - * thread. This required rototiller to move what was previously the main - * thread's duties - page rendering dispatch, to a separate thread. - */ - - -/* Most of fb_page_t is kept private, the public part is - * just an fb_fragment_t describing the whole page. - */ -typedef struct _fb_page_t _fb_page_t; -struct _fb_page_t { - void *ops_page; - - _fb_page_t *next, *previous; - fb_page_t public_page; -}; - -typedef struct fb_t { - const fb_ops_t *ops; - void *ops_context; - int n_pages; - - pthread_mutex_t rebuild_mutex; - int rebuild_pages; /* counter of pages needing a rebuild */ - - _fb_page_t *active_page; /* page currently displayed */ - - pthread_mutex_t ready_mutex; - pthread_cond_t ready_cond; - _fb_page_t *ready_pages_head; /* next pages to flip to */ - _fb_page_t *ready_pages_tail; - - pthread_mutex_t inactive_mutex; - pthread_cond_t inactive_cond; - _fb_page_t *inactive_pages_head; /* finished pages available for (re)use */ - _fb_page_t *inactive_pages_tail; - - unsigned put_pages_count; -} fb_t; - -#ifndef container_of -#define container_of(_ptr, _type, _member) \ - (_type *)((void *)(_ptr) - offsetof(_type, _member)) -#endif - - -/* Consumes ready pages queued via fb_page_put(), submits them to drm to flip - * on vsync. Produces inactive pages from those replaced, making them - * available to fb_page_get(). */ -int fb_flip(fb_t *fb) -{ - _fb_page_t *next_active_page; - int r; - - /* wait for a flip req, submit the req page for flip on vsync, wait for it to flip before making the - * active page inactive/available, repeat. - */ - pthread_mutex_lock(&fb->ready_mutex); - while (!fb->ready_pages_head) - pthread_cond_wait(&fb->ready_cond, &fb->ready_mutex); - - next_active_page = fb->ready_pages_head; - fb->ready_pages_head = next_active_page->next; - if (!fb->ready_pages_head) - fb->ready_pages_tail = NULL; - pthread_mutex_unlock(&fb->ready_mutex); - - /* submit the next active page for page flip on vsync, and wait for it. */ - r = fb->ops->page_flip(fb, fb->ops_context, next_active_page->ops_page); - if (r < 0) /* TODO: vet this: what happens to this page? */ - return r; - - /* now that we're displaying a new page, make the previously active one inactive so rendering can reuse it */ - pthread_mutex_lock(&fb->inactive_mutex); - fb->active_page->next = fb->inactive_pages_head; - fb->inactive_pages_head = fb->active_page; - fb->inactive_pages_head->previous = NULL; - if (fb->inactive_pages_head->next) - fb->inactive_pages_head->next->previous = fb->inactive_pages_head; - else - fb->inactive_pages_tail = fb->inactive_pages_head; - - /* before setting the renderer loose, check if there's more page rebuilding needed, - * and if there is do as much as possible here in the inactive set. Note it's important - * that the renderer take pages from the tail, and we always replenish inactive at the - * head, as well as rebuild pages from the head. - */ - pthread_mutex_lock(&fb->rebuild_mutex); - for (_fb_page_t *p = fb->inactive_pages_head; p && fb->rebuild_pages > 0; p = p->next) { - fb->ops->page_free(fb, fb->ops_context, p->ops_page); - p->ops_page = fb->ops->page_alloc(fb, fb->ops_context, &p->public_page); - fb->rebuild_pages--; - } - pthread_mutex_unlock(&fb->rebuild_mutex); - - pthread_cond_signal(&fb->inactive_cond); - pthread_mutex_unlock(&fb->inactive_mutex); - - fb->active_page = next_active_page; - - return 0; -} - - -/* acquire the fb, making page the visible page */ -static int fb_acquire(fb_t *fb, _fb_page_t *page) -{ - int ret; - - ret = fb->ops->acquire(fb, fb->ops_context, page->ops_page); - if (ret < 0) - return ret; - - fb->active_page = page; - - return 0; -} - - -/* release the fb, making the visible page inactive */ -static void fb_release(fb_t *fb) -{ - fb->ops->release(fb, fb->ops_context); - - /* XXX: this is getting silly, either add a doubly linked list header or - * at least use some functions for this local to this file. - */ - fb->active_page->next = fb->inactive_pages_head; - fb->inactive_pages_head = fb->active_page; - fb->inactive_pages_head->previous = NULL; - if (fb->inactive_pages_head->next) - fb->inactive_pages_head->next->previous = fb->inactive_pages_head; - else - fb->inactive_pages_tail = fb->inactive_pages_head; - - fb->active_page = NULL; -} - - -/* creates a framebuffer page */ -static void fb_page_new(fb_t *fb) -{ - _fb_page_t *page; - - page = calloc(1, sizeof(_fb_page_t)); - assert(page); - - page->ops_page = fb->ops->page_alloc(fb, fb->ops_context, &page->public_page); - - pthread_mutex_lock(&fb->inactive_mutex); - page->next = fb->inactive_pages_head; - fb->inactive_pages_head = page; - if (fb->inactive_pages_head->next) - fb->inactive_pages_head->next->previous = fb->inactive_pages_head; - else - fb->inactive_pages_tail = fb->inactive_pages_head; - pthread_mutex_unlock(&fb->inactive_mutex); - -} - - -static void _fb_page_free(fb_t *fb, _fb_page_t *page) -{ - fb->ops->page_free(fb, fb->ops_context, page->ops_page); - - free(page); -} - - -/* get the next inactive page from the fb, waiting if necessary. */ -static inline _fb_page_t * _fb_page_get(fb_t *fb) -{ - _fb_page_t *page; - - /* As long as n_pages is >= 3 this won't block unless we're submitting - * pages faster than vhz. - */ - pthread_mutex_lock(&fb->inactive_mutex); - while (!(page = fb->inactive_pages_tail)) - pthread_cond_wait(&fb->inactive_cond, &fb->inactive_mutex); - fb->inactive_pages_tail = page->previous; - if (fb->inactive_pages_tail) - fb->inactive_pages_tail->next = NULL; - else - fb->inactive_pages_head = NULL; - pthread_mutex_unlock(&fb->inactive_mutex); - - page->next = page->previous = NULL; - page->public_page.fragment.zeroed = 0; - - return page; -} - - -/* public interface */ -fb_page_t * fb_page_get(fb_t *fb) -{ - return &(_fb_page_get(fb)->public_page); -} - - -/* put a page into the fb, queueing for display */ -static inline void _fb_page_put(fb_t *fb, _fb_page_t *page) -{ - pthread_mutex_lock(&fb->ready_mutex); - if (fb->ready_pages_tail) - fb->ready_pages_tail->next = page; - else - fb->ready_pages_head = page; - - fb->ready_pages_tail = page; - pthread_cond_signal(&fb->ready_cond); - pthread_mutex_unlock(&fb->ready_mutex); -} - - -/* public interface */ - -/* put a page into the fb, queueing for display */ -void fb_page_put(fb_t *fb, fb_page_t *page) -{ - fb->put_pages_count++; - - _fb_page_put(fb, container_of(page, _fb_page_t, public_page)); -} - - -/* get (and reset) the current count of put pages */ -void fb_get_put_pages_count(fb_t *fb, unsigned *count) -{ - *count = fb->put_pages_count; - fb->put_pages_count = 0; -} - - -/* free the fb and associated resources */ -fb_t * fb_free(fb_t *fb) -{ - if (fb) { - if (fb->active_page) - fb_release(fb); - - /* TODO: free all the pages */ - - if (fb->ops->shutdown && fb->ops_context) - fb->ops->shutdown(fb, fb->ops_context); - - pthread_mutex_destroy(&fb->ready_mutex); - pthread_cond_destroy(&fb->ready_cond); - pthread_mutex_destroy(&fb->inactive_mutex); - pthread_cond_destroy(&fb->inactive_cond); - - free(fb); - } - - return NULL; -} - - -/* create a new fb instance */ -int fb_new(const fb_ops_t *ops, settings_t *settings, int n_pages, fb_t **res_fb) -{ - _fb_page_t *page; - fb_t *fb; - int r; - - assert(ops); - assert(ops->page_alloc); - assert(ops->page_free); - assert(ops->page_flip); - assert(n_pages > 1); - assert(res_fb); - - /* XXX: page-flipping is the only supported rendering model, requiring 2+ pages. */ - if (n_pages < 2) - return -EINVAL; - - fb = calloc(1, sizeof(fb_t)); - if (!fb) - return -ENOMEM; - - fb->ops = ops; - if (ops->init) { - r = ops->init(settings, &fb->ops_context); - if (r < 0) - goto fail; - } - - for (int i = 0; i < n_pages; i++) - fb_page_new(fb); - - fb->n_pages = n_pages; - - pthread_mutex_init(&fb->ready_mutex, NULL); - pthread_cond_init(&fb->ready_cond, NULL); - pthread_mutex_init(&fb->inactive_mutex, NULL); - pthread_cond_init(&fb->inactive_cond, NULL); - pthread_mutex_init(&fb->rebuild_mutex, NULL); - - page = _fb_page_get(fb); - if (!page) { - r = -ENOMEM; - goto fail; - } - - r = fb_acquire(fb, page); - if (r < 0) - goto fail; - - *res_fb = fb; - - return r; - -fail: - fb_free(fb); - - return r; -} - - -/* This informs the fb to reconstruct its pages as they become inactive, - * giving the backend an opportunity to reconfigure them before they get - * rendered to again. It's intended to be used in response to window - * resizes. - */ -void fb_rebuild(fb_t *fb) -{ - assert(fb); - - /* TODO: this could easily be an atomic counter since we have no need for waiting */ - pthread_mutex_lock(&fb->rebuild_mutex); - fb->rebuild_pages = fb->n_pages; - pthread_mutex_unlock(&fb->rebuild_mutex); -} - - -/* helpers for fragmenting incrementally */ -int fb_fragment_slice_single(const fb_fragment_t *fragment, unsigned n_fragments, unsigned number, fb_fragment_t *res_fragment) -{ - unsigned slice = fragment->height / n_fragments; - unsigned yoff = slice * number; - unsigned pitch; - - if (yoff >= fragment->height) - return 0; - - res_fragment->buf = ((void *)fragment->buf) + yoff * fragment->pitch; - res_fragment->x = fragment->x; - res_fragment->y = yoff; - res_fragment->width = fragment->width; - res_fragment->height = MIN(fragment->height - yoff, slice); - res_fragment->frame_width = fragment->frame_width; - res_fragment->frame_height = fragment->frame_height; - res_fragment->stride = fragment->stride; - res_fragment->pitch = fragment->pitch; - res_fragment->number = number; - res_fragment->zeroed = fragment->zeroed; - - return 1; -} - - -int fb_fragment_tile_single(const fb_fragment_t *fragment, unsigned tile_size, unsigned number, fb_fragment_t *res_fragment) -{ - unsigned w = fragment->width / tile_size, h = fragment->height / tile_size; - unsigned x, y, xoff, yoff; - - if (w * tile_size < fragment->width) - w++; - - if (h * tile_size < fragment->height) - h++; - - y = number / w; - if (y >= h) - return 0; - - x = number - (y * w); - - xoff = x * tile_size; - yoff = y * tile_size; - - res_fragment->buf = (void *)fragment->buf + (yoff * fragment->pitch) + (xoff * 4); - res_fragment->x = fragment->x + xoff; - res_fragment->y = fragment->y + yoff; - res_fragment->width = MIN(fragment->width - xoff, tile_size); - res_fragment->height = MIN(fragment->height - yoff, tile_size); - res_fragment->frame_width = fragment->frame_width; - res_fragment->frame_height = fragment->frame_height; - res_fragment->stride = fragment->stride + ((fragment->width - res_fragment->width) * 4); - res_fragment->pitch = fragment->pitch; - res_fragment->number = number; - - return 1; -} diff --git a/src/fb.h b/src/fb.h deleted file mode 100644 index 9f87b3d..0000000 --- a/src/fb.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef _FB_H -#define _FB_H - -#include -#include - -#include "settings.h" - -/* All renderers should target fb_fragment_t, which may or may not represent - * a full-screen mmap. Helpers are provided for subdividing fragments for - * concurrent renderers. - */ -typedef struct fb_fragment_t { - uint32_t *buf; /* pointer to the first pixel in the fragment */ - unsigned x, y; /* absolute coordinates of the upper left corner of this fragment */ - unsigned width, height; /* width and height of this fragment */ - unsigned frame_width; /* width of the frame this fragment is part of */ - unsigned frame_height; /* height of the frame this fragment is part of */ - unsigned stride; /* number of bytes from the end of one row to the start of the next */ - unsigned pitch; /* number of bytes separating y from y + 1, including any padding */ - unsigned number; /* this fragment's number as produced by fragmenting */ - unsigned zeroed:1; /* if this fragment has been zeroed since last flip */ -} fb_fragment_t; - -/* This is a page handle object for page flip submission/life-cycle. - * Outside of fb_page_get()/fb_page_put(), you're going to be interested in - * fb_fragment_t. The fragment included here describes the whole page, - * it may be divided via fb_fragment_divide(). - */ -typedef struct fb_page_t { - fb_fragment_t fragment; -} fb_page_t; - -typedef struct fb_t fb_t; - -/* Supply this struct to fb_new() with the appropriate context */ -typedef struct fb_ops_t { - int (*setup)(const settings_t *settings, setting_desc_t **next); - int (*init)(const settings_t *settings, void **res_context); - void (*shutdown)(fb_t *fb, void *context); - int (*acquire)(fb_t *fb, void *context, void *page); - void (*release)(fb_t *fb, void *context); - void * (*page_alloc)(fb_t *fb, void *context, fb_page_t *res_page); - int (*page_free)(fb_t *fb, void *context, void *page); - int (*page_flip)(fb_t *fb, void *context, void *page); -} fb_ops_t; - -fb_page_t * fb_page_get(fb_t *fb); -void fb_page_put(fb_t *fb, fb_page_t *page); -fb_t * fb_free(fb_t *fb); -void fb_get_put_pages_count(fb_t *fb, unsigned *count); -int fb_new(const fb_ops_t *ops, settings_t *settings, int n_pages, fb_t **res_fb); -void fb_rebuild(fb_t *fb); -void * fb_context(fb_t *fb); -int fb_flip(fb_t *fb); -void fb_fragment_divide(fb_fragment_t *fragment, unsigned n_fragments, fb_fragment_t fragments[]); -int fb_fragment_slice_single(const fb_fragment_t *fragment, unsigned n_fragments, unsigned num, fb_fragment_t *res_fragment); -int fb_fragment_tile_single(const fb_fragment_t *fragment, unsigned tile_size, unsigned num, fb_fragment_t *res_fragment); - - -/* checks if a coordinate is contained within a fragment */ -static inline int fb_fragment_contains(fb_fragment_t *fragment, int x, int y) -{ - if (x < fragment->x || x >= fragment->x + fragment->width || - y < fragment->y || y >= fragment->y + fragment->height) - return 0; - - return 1; -} - - -/* puts a pixel into the fragment, no bounds checking is performed. */ -static inline void fb_fragment_put_pixel_unchecked(fb_fragment_t *fragment, int x, int y, uint32_t pixel) -{ - uint32_t *pixels = ((void *)fragment->buf) + (y - fragment->y) * fragment->pitch; - - pixels[x - fragment->x] = pixel; -} - - -/* puts a pixel into the fragment, bounds checking is performed with a draw performed return status */ -static inline int fb_fragment_put_pixel_checked(fb_fragment_t *fragment, int x, int y, uint32_t pixel) -{ - if (!fb_fragment_contains(fragment, x, y)) - return 0; - - fb_fragment_put_pixel_unchecked(fragment, x, y, pixel); - - return 1; -} - - -/* zero a fragment */ -static inline void fb_fragment_zero(fb_fragment_t *fragment) -{ - void *buf = fragment->buf; - - if (fragment->zeroed) - return; - - /* TODO: there should be a fast-path for non-divided fragments where there's no stride to skip */ - for (int y = 0; y < fragment->height; y++, buf += fragment->pitch) - memset(buf, 0, fragment->pitch - fragment->stride); - - fragment->zeroed = 1; -} - -#endif diff --git a/src/fps.c b/src/fps.c index 57f67a7..30b65cf 100644 --- a/src/fps.c +++ b/src/fps.c @@ -2,8 +2,8 @@ #include #include -#include "fb.h" -#include "util.h" +#include "til_fb.h" +#include "til_util.h" static int print_fps; @@ -36,7 +36,7 @@ int fps_setup(void) } -void fps_print(fb_t *fb) +void fps_print(til_fb_t *fb) { #ifdef __WIN32__ @@ -46,7 +46,7 @@ void fps_print(fb_t *fb) if (!print_fps) return; - fb_get_put_pages_count(fb, &n); + til_fb_get_put_pages_count(fb, &n); printf("FPS: %u\n", n); print_fps = 0; diff --git a/src/fps.h b/src/fps.h index 1f986c7..1afb566 100644 --- a/src/fps.h +++ b/src/fps.h @@ -1,9 +1,9 @@ #ifndef _FPS_H #define _FPS_H -#include "fb.h" +#include "til_fb.h" int fps_setup(void); -void fps_print(fb_t *fb); +void fps_print(til_fb_t *fb); #endif diff --git a/src/knobs.h b/src/knobs.h deleted file mode 100644 index 25c13eb..0000000 --- a/src/knobs.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef _KNOBS_H -#define _KNOBS_H - -#include - -/* A knob exposes a binding for some float in a module's context - * which can be varied at runtime between frames to influence - * the output. There's some overlap with settings, but settings - * are more intended for configuration applied at context - * creation, which won't vary frame-to-frame, but may influence - * the initial value and/or automatic behavior of knobs for - * instance, or even which knobs are available. - * - * At this time knobs will only apply to floats, accompanied by - * some rudimentary bounds. - * - * Integer types would probably be useful, and maybe a precision - * specifier, those can be added in the future as needed, but I'd - * like to keep it simple for now and see what kind of problems - * emerge. - * - * The current expectation is that a module context struct will - * incorporate an array of knobs, replacing loose floats already - * being automatically varied within the module frame-to-frame. - * - * The module will then use the knob_auto_* helpers below to - * access and manipulate the values, instead of directly - * accessing the loose floats as before. - * - * External manipulators of the knobs will use the knob_* - * helpers, instead of the knob_auto_* helpers, to - * access+manipulate the knobs. These helpers are basically just - * to get external and internal manipulators to agree on which - * side owns control via the managed field. - */ -typedef struct knob_t { - const char *name; /* Short API-oriented name */ - const char *desc; /* Longer UI-oriented name */ - const float min, max; /* Value bounds */ - float value; /* Value knob affects */ - unsigned managed:1; /* Set when knob control of value is active, - * suppress automagic control of value when set. - */ -} knob_t; - - -/* helper for modules automating knob controls, use this to - * change values intead of direct manipulation to respect active. - * returns new (or unchanged) value - */ -static inline float knob_auto_set(knob_t *knob, float value) -{ - assert(knob); - - if (knob->managed) - return knob->value; - - return knob->value = value; -} - -/* identical to knob_auto_set, except adds to existing value. - */ -static inline float knob_auto_add(knob_t *knob, float value) -{ - assert(knob); - - return knob_auto_set(knob, knob->value + value); -} - - -/* identical to knob_auto* variants, except intended for - * external knob-twisters, i.e. the "managed" knob entrypoints. - */ -static inline float knob_set(knob_t *knob, float value) -{ - assert(knob); - - knob->managed = 1; - - return knob->value = value; -} - - -static inline float knob_add(knob_t *knob, float value) -{ - assert(knob); - - return knob_set(knob, knob->value + value); -} - -#endif diff --git a/src/libs/ray/ray_camera.c b/src/libs/ray/ray_camera.c index a0e3d02..4e01877 100644 --- a/src/libs/ray/ray_camera.c +++ b/src/libs/ray/ray_camera.c @@ -1,4 +1,4 @@ -#include "fb.h" +#include "til_fb.h" #include "ray_camera.h" #include "ray_euler.h" @@ -51,7 +51,7 @@ void ray_camera_frame_prepare(const ray_camera_t *camera, unsigned frame_width, /* Begin a frame's fragment, initializing frame and ray. */ -void ray_camera_fragment_begin(ray_camera_frame_t *frame, fb_fragment_t *fb_fragment, ray_ray_t *res_ray, ray_camera_fragment_t *res_fragment) +void ray_camera_fragment_begin(ray_camera_frame_t *frame, til_fb_fragment_t *fb_fragment, ray_ray_t *res_ray, ray_camera_fragment_t *res_fragment) { res_fragment->frame = frame; res_fragment->fb_fragment = fb_fragment; diff --git a/src/libs/ray/ray_camera.h b/src/libs/ray/ray_camera.h index 0a8af2a..06bb2db 100644 --- a/src/libs/ray/ray_camera.h +++ b/src/libs/ray/ray_camera.h @@ -3,7 +3,7 @@ #include -#include "fb.h" +#include "til_fb.h" #include "ray_3f.h" #include "ray_euler.h" @@ -39,7 +39,7 @@ typedef struct ray_camera_frame_t { typedef struct ray_camera_fragment_t { ray_camera_frame_t *frame; /* the frame supplied to fragment_begin() */ - fb_fragment_t *fb_fragment; /* the fragment supplied to fragment_begin() */ + til_fb_fragment_t *fb_fragment; /* the fragment supplied to fragment_begin() */ ray_ray_t *ray; /* the ray supplied to frame_begin(), which gets updated as we step through the frame. */ ray_3f_t cur_w, cur_e; /* current row's west and east ends */ @@ -49,7 +49,7 @@ typedef struct ray_camera_fragment_t { void ray_camera_frame_prepare(const ray_camera_t *camera, unsigned frame_width, unsigned frame_height, ray_camera_frame_t *res_frame); -void ray_camera_fragment_begin(ray_camera_frame_t *frame, fb_fragment_t *fb_fragment, ray_ray_t *res_ray, ray_camera_fragment_t *res_fragment); +void ray_camera_fragment_begin(ray_camera_frame_t *frame, til_fb_fragment_t *fb_fragment, ray_ray_t *res_ray, ray_camera_fragment_t *res_fragment); /* Step the ray through the fragment on the x axis, returns 1 when rays remain on this axis, 0 at the end. */ diff --git a/src/libs/ray/ray_render.c b/src/libs/ray/ray_render.c index dbbfb47..535b71a 100644 --- a/src/libs/ray/ray_render.c +++ b/src/libs/ray/ray_render.c @@ -1,7 +1,7 @@ #include #include -#include "fb.h" +#include "til_fb.h" #include "ray_camera.h" #include "ray_color.h" @@ -200,7 +200,7 @@ static inline ray_color_t trace_ray(ray_render_t *render, ray_ray_t *primary_ray } -void ray_render_trace_fragment(ray_render_t *render, fb_fragment_t *fb_fragment) +void ray_render_trace_fragment(ray_render_t *render, til_fb_fragment_t *fb_fragment) { uint32_t *buf = fb_fragment->buf; ray_camera_fragment_t fragment; diff --git a/src/libs/ray/ray_render.h b/src/libs/ray/ray_render.h index 69daf86..e6597d1 100644 --- a/src/libs/ray/ray_render.h +++ b/src/libs/ray/ray_render.h @@ -1,7 +1,7 @@ #ifndef _RAY_RENDER_H #define _RAY_RENDER_H -#include "fb.h" +#include "til_fb.h" #include "ray_camera.h" #include "ray_scene.h" @@ -10,6 +10,6 @@ typedef struct ray_render_t ray_render_t; ray_render_t * ray_render_new(const ray_scene_t *scene, const ray_camera_t *camera, unsigned frame_width, unsigned frame_height); void ray_render_free(ray_render_t *render); -void ray_render_trace_fragment(ray_render_t *render, fb_fragment_t *fb_fragment); +void ray_render_trace_fragment(ray_render_t *render, til_fb_fragment_t *fb_fragment); #endif diff --git a/src/libs/txt/txt.c b/src/libs/txt/txt.c index e42d8c2..02b753f 100644 --- a/src/libs/txt/txt.c +++ b/src/libs/txt/txt.c @@ -2,7 +2,7 @@ #include #include -#include "fb.h" +#include "til_fb.h" #include "ascii/ascii.h" #include "txt.h" @@ -153,19 +153,19 @@ static int overlaps(int x1, int y1, unsigned w1, unsigned h1, int x2, int y2, un } -static inline void draw_char(fb_fragment_t *fragment, uint32_t color, int x, int y, char c) +static inline void draw_char(til_fb_fragment_t *fragment, uint32_t color, int x, int y, char c) { /* TODO: this could be optimized to skip characters with no overlap */ for (int i = 0; i < ASCII_HEIGHT; i++) { for (int j = 0; j < ASCII_WIDTH; j++) { if (ascii_chars[c][i * ASCII_WIDTH + j]) - fb_fragment_put_pixel_checked(fragment, x + j, y + i, color); + til_fb_fragment_put_pixel_checked(fragment, x + j, y + i, color); } } } -void txt_render_fragment(txt_t *txt, fb_fragment_t *fragment, uint32_t color, int x, int y, txt_align_t alignment) +void txt_render_fragment(txt_t *txt, til_fb_fragment_t *fragment, uint32_t color, int x, int y, txt_align_t alignment) { int jx, jy, col, row; char c, *str; diff --git a/src/libs/txt/txt.h b/src/libs/txt/txt.h index 8c68e30..a924b25 100644 --- a/src/libs/txt/txt.h +++ b/src/libs/txt/txt.h @@ -3,7 +3,7 @@ #include -typedef struct fb_fragment_t fb_fragment_t; +typedef struct til_fb_fragment_t til_fb_fragment_t; typedef struct txt_t txt_t; typedef enum txt_halign_t { @@ -28,6 +28,6 @@ typedef struct txt_align_t { txt_t * txt_new(const char *str); txt_t * txt_newf(const char *fmt, ...); txt_t * txt_free(txt_t *txt); -void txt_render_fragment(txt_t *txt, fb_fragment_t *fragment, uint32_t color, int x, int y, txt_align_t alignment); +void txt_render_fragment(txt_t *txt, til_fb_fragment_t *fragment, uint32_t color, int x, int y, txt_align_t alignment); #endif diff --git a/src/main.c b/src/main.c index 5180529..c028998 100644 --- a/src/main.c +++ b/src/main.c @@ -10,12 +10,13 @@ #include #include -#include "settings.h" -#include "setup.h" -#include "fb.h" +#include "til.h" +#include "til_settings.h" +#include "til_fb.h" +#include "til_util.h" + #include "fps.h" -#include "rototiller.h" -#include "util.h" +#include "setup.h" /* Copyright (C) 2016 Vito Caputo */ @@ -27,17 +28,17 @@ */ #define DEFAULT_VIDEO "sdl" -extern fb_ops_t drm_fb_ops; -extern fb_ops_t sdl_fb_ops; -fb_ops_t *fb_ops; +extern til_fb_ops_t drm_fb_ops; +extern til_fb_ops_t sdl_fb_ops; +static til_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; + const til_module_t *module; + void *module_context; + pthread_t thread; + til_fb_t *fb; + struct timeval start_tv; + unsigned ticks_offset; } rototiller_t; static rototiller_t rototiller; @@ -86,8 +87,8 @@ static int parse_argv(int argc, const char *argv[], argv_t *res_args) typedef struct setup_t { - settings_t *module; - settings_t *video; + til_settings_t *module; + til_settings_t *video; } setup_t; /* FIXME: this is unnecessarily copy-pasta, i think modules should just be made @@ -96,24 +97,24 @@ typedef struct setup_t { */ /* select video backend if not yet selected, then setup the selected backend. */ -static int setup_video(settings_t *settings, setting_desc_t **next_setting) +static int setup_video(til_settings_t *settings, til_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); + video = til_settings_get_key(settings, 0); if (!video) { - setting_desc_t *desc; - const char *values[] = { + til_setting_desc_t *desc; + const char *values[] = { #ifdef HAVE_DRM - "drm", + "drm", #endif - "sdl", - NULL, - }; - int r; + "sdl", + NULL, + }; + int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Video Backend", .key = NULL, .regex = "[a-z]+", @@ -152,21 +153,21 @@ 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); + setup.module = til_settings_new(args->module); if (!setup.module) return -ENOMEM; - setup.video = settings_new(args->video); + setup.video = til_settings_new(args->video); if (!setup.video) { - settings_free(setup.module); + til_settings_free(setup.module); return -ENOMEM; } - r = setup_interactively(setup.module, rototiller_module_setup, args->use_defaults); + r = setup_interactively(setup.module, til_module_setup, args->use_defaults); if (r < 0) { - settings_free(setup.module); - settings_free(setup.video); + til_settings_free(setup.module); + til_settings_free(setup.video); return r; } @@ -176,8 +177,8 @@ static int setup_from_args(argv_t *args, setup_t *res_setup) r = setup_interactively(setup.video, setup_video, args->use_defaults); if (r < 0) { - settings_free(setup.module); - settings_free(setup.video); + til_settings_free(setup.module); + til_settings_free(setup.video); return r; } @@ -197,14 +198,14 @@ static int print_setup_as_args(setup_t *setup) char buf[64]; int r; - module_args = settings_as_arg(setup->module); + module_args = til_settings_as_arg(setup->module); if (!module_args) { r = -ENOMEM; goto _out; } - video_args = settings_as_arg(setup->video); + video_args = til_settings_as_arg(setup->video); if (!video_args) { r = -ENOMEM; @@ -255,17 +256,17 @@ static void * rototiller_thread(void *_rt) struct timeval now; for (;;) { - fb_page_t *page; + til_fb_page_t *page; unsigned ticks; - page = fb_page_get(rt->fb); + page = til_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); + til_module_render(rt->module, rt->module_context, ticks, &page->fragment); - fb_page_put(rt->fb, page); + til_fb_page_put(rt->fb, page); } return NULL; @@ -296,20 +297,20 @@ int main(int argc, const char *argv[]) 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(!(rototiller.module = til_lookup_module(til_settings_get_key(setup.module, 0))), + "unable to lookup module from settings \"%s\"", til_settings_get_key(setup.module, 0)); - exit_if((r = fb_new(fb_ops, setup.video, NUM_FB_PAGES, &rototiller.fb)) < 0, + exit_if((r = til_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, + exit_if((r = til_init()) < 0, "unable to initialize librototiller: %s", strerror(-r)); gettimeofday(&rototiller.start_tv, NULL); - exit_if((r = rototiller_module_create_context( + exit_if((r = til_module_create_context( rototiller.module, get_ticks(&rototiller.start_tv, &rototiller.start_tv, @@ -321,7 +322,7 @@ int main(int argc, const char *argv[]) "unable to create dispatch thread"); for (;;) { - if (fb_flip(rototiller.fb) < 0) + if (til_fb_flip(rototiller.fb) < 0) break; fps_print(rototiller.fb); @@ -329,12 +330,12 @@ int main(int argc, const char *argv[]) pthread_cancel(rototiller.thread); pthread_join(rototiller.thread, NULL); - rototiller_shutdown(); + til_shutdown(); if (rototiller.module_context) rototiller.module->destroy_context(rototiller.module_context); - fb_free(rototiller.fb); + til_fb_free(rototiller.fb); return EXIT_SUCCESS; } diff --git a/src/modules/compose/compose.c b/src/modules/compose/compose.c index 5cf994e..bf3f125 100644 --- a/src/modules/compose/compose.c +++ b/src/modules/compose/compose.c @@ -1,11 +1,12 @@ #include #include -#include "fb.h" -#include "rototiller.h" -#include "settings.h" +#include "til.h" +#include "til_fb.h" +#include "til_settings.h" +#include "til_util.h" + #include "txt/txt.h" -#include "util.h" /* Copyright (C) 2020 - Vito Caputo */ @@ -23,28 +24,28 @@ */ typedef struct compose_layer_t { - const rototiller_module_t *module; - void *module_ctxt; - char *settings; + const til_module_t *module; + void *module_ctxt; + char *settings; } compose_layer_t; typedef struct compose_context_t { - unsigned n_cpus; + unsigned n_cpus; - size_t n_layers; - compose_layer_t layers[]; + size_t n_layers; + compose_layer_t layers[]; } compose_context_t; static void * compose_create_context(unsigned ticks, unsigned num_cpus); static void compose_destroy_context(void *context); -static void compose_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter); -static int compose_setup(const settings_t *settings, setting_desc_t **next_setting); +static void compose_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter); +static int compose_setup(const til_settings_t *settings, til_setting_desc_t **next_setting); static char *compose_default_layers[] = { "drizzle", "stars", "spiro", "plato", NULL }; static char **compose_layers; -rototiller_module_t compose_module = { +til_module_t compose_module = { .create_context = compose_create_context, .destroy_context = compose_destroy_context, .prepare_frame = compose_prepare_frame, @@ -72,9 +73,9 @@ static void * compose_create_context(unsigned ticks, unsigned num_cpus) ctxt->n_cpus = num_cpus; for (int i = 0; i < n; i++) { - const rototiller_module_t *module; + const til_module_t *module; - module = rototiller_lookup_module(layers[i]); + module = til_lookup_module(layers[i]); ctxt->layers[i].module = module; if (module->create_context) @@ -99,26 +100,26 @@ static void compose_destroy_context(void *context) } -static void compose_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void compose_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { compose_context_t *ctxt = context; - fb_fragment_zero(fragment); + til_fb_fragment_zero(fragment); for (int i = 0; i < ctxt->n_layers; i++) - rototiller_module_render(ctxt->layers[i].module, ctxt->layers[i].module_ctxt, ticks, fragment); + til_module_render(ctxt->layers[i].module, ctxt->layers[i].module_ctxt, ticks, fragment); } -static int compose_setup(const settings_t *settings, setting_desc_t **next_setting) +static int compose_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) { const char *layers; - layers = settings_get_value(settings, "layers"); + layers = til_settings_get_value(settings, "layers"); if (!layers) { int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Colon-Separated List Of Module Layers, In Draw Order", .key = "layers", .preferred = "drizzle:stars:spiro:plato", @@ -132,12 +133,12 @@ static int compose_setup(const settings_t *settings, setting_desc_t **next_setti /* turn layers colon-separated list into a null-terminated array of strings */ { - const rototiller_module_t **modules; + const til_module_t **modules; size_t n_modules; char *toklayers, *layer; int n = 2; - rototiller_get_modules(&modules, &n_modules); + til_get_modules(&modules, &n_modules); toklayers = strdup(layers); if (!toklayers) diff --git a/src/modules/drizzle/drizzle.c b/src/modules/drizzle/drizzle.c index f546cea..f0ed956 100644 --- a/src/modules/drizzle/drizzle.c +++ b/src/modules/drizzle/drizzle.c @@ -17,9 +17,10 @@ #include #include -#include "fb.h" +#include "til.h" +#include "til_fb.h" + #include "puddle/puddle.h" -#include "rototiller.h" #define PUDDLE_SIZE 512 #define DRIZZLE_CNT 20 @@ -92,15 +93,15 @@ static void drizzle_destroy_context(void *context) } -static int drizzle_fragmenter(void *context, const fb_fragment_t *fragment, unsigned number, fb_fragment_t *res_fragment) +static int drizzle_fragmenter(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment) { drizzle_context_t *ctxt = context; - return fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); + return til_fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); } -static void drizzle_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void drizzle_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { drizzle_context_t *ctxt = context; @@ -124,7 +125,7 @@ static void drizzle_prepare_frame(void *context, unsigned ticks, unsigned n_cpus } -static void drizzle_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void drizzle_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { drizzle_context_t *ctxt = context; float xf = 1.f / (float)fragment->frame_width; @@ -142,7 +143,7 @@ static void drizzle_render_fragment(void *context, unsigned ticks, unsigned cpu, color.z = puddle_sample(ctxt->puddle, &coord); pixel = color_to_uint32(color); - fb_fragment_put_pixel_unchecked(fragment, x, y, pixel); + til_fb_fragment_put_pixel_unchecked(fragment, x, y, pixel); coord.x += xf; } @@ -152,7 +153,7 @@ static void drizzle_render_fragment(void *context, unsigned ticks, unsigned cpu, } -static int drizzle_setup(const settings_t *settings, setting_desc_t **next_setting) +static int drizzle_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) { const char *viscosity; const char *values[] = { @@ -163,15 +164,15 @@ static int drizzle_setup(const settings_t *settings, setting_desc_t **next_setti NULL }; - viscosity = settings_get_value(settings, "viscosity"); + viscosity = til_settings_get_value(settings, "viscosity"); if (!viscosity) { int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Puddle Viscosity", .key = "viscosity", .regex = "\\.[0-9]+", - .preferred = SETTINGS_STR(DEFAULT_VISCOSITY), + .preferred = TIL_SETTINGS_STR(DEFAULT_VISCOSITY), .values = values, .annotations = NULL }, next_setting); @@ -187,7 +188,7 @@ static int drizzle_setup(const settings_t *settings, setting_desc_t **next_setti } -rototiller_module_t drizzle_module = { +til_module_t drizzle_module = { .create_context = drizzle_create_context, .destroy_context = drizzle_destroy_context, .prepare_frame = drizzle_prepare_frame, diff --git a/src/modules/flui2d/flui2d.c b/src/modules/flui2d/flui2d.c index 71238cd..3b0e629 100644 --- a/src/modules/flui2d/flui2d.c +++ b/src/modules/flui2d/flui2d.c @@ -3,9 +3,9 @@ #include #include -#include "fb.h" -#include "rototiller.h" -#include "settings.h" +#include "til.h" +#include "til_fb.h" +#include "til_settings.h" /* This code is almost entirely taken from the paper: @@ -208,14 +208,14 @@ static void flui2d_destroy_context(void *context) } -static int flui2d_fragmenter(void *context, const fb_fragment_t *fragment, unsigned number, fb_fragment_t *res_fragment) +static int flui2d_fragmenter(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment) { - return fb_fragment_tile_single(fragment, 64, number, res_fragment); + return til_fb_fragment_tile_single(fragment, 64, number, res_fragment); } /* Prepare a frame for concurrent drawing of fragment using multiple fragments */ -static void flui2d_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void flui2d_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { flui2d_context_t *ctxt = context; float r = (ticks % (unsigned)(2 * M_PI * 1000)) * .001f; @@ -247,7 +247,7 @@ static void flui2d_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, /* Draw a the flui2d densities */ -static void flui2d_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void flui2d_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { flui2d_context_t *ctxt = context; @@ -277,14 +277,14 @@ static void flui2d_render_fragment(void *context, unsigned ticks, unsigned cpu, pixel = ((float)dens * 256.f); pixel = pixel << 16 | pixel << 8 | pixel; - fb_fragment_put_pixel_unchecked(fragment, x, y, pixel); + til_fb_fragment_put_pixel_unchecked(fragment, x, y, pixel); } } } /* Settings hooks for configurable variables */ -static int flui2d_setup(const settings_t *settings, setting_desc_t **next_setting) +static int flui2d_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) { const char *viscosity; const char *diffusion; @@ -301,15 +301,15 @@ static int flui2d_setup(const settings_t *settings, setting_desc_t **next_settin }; - viscosity = settings_get_value(settings, "viscosity"); + viscosity = til_settings_get_value(settings, "viscosity"); if (!viscosity) { int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Fluid Viscosity", .key = "viscosity", .regex = "\\.[0-9]+", - .preferred = SETTINGS_STR(DEFAULT_VISCOSITY), + .preferred = TIL_SETTINGS_STR(DEFAULT_VISCOSITY), .values = values, .annotations = NULL }, next_setting); @@ -319,15 +319,15 @@ static int flui2d_setup(const settings_t *settings, setting_desc_t **next_settin return 1; } - diffusion = settings_get_value(settings, "diffusion"); + diffusion = til_settings_get_value(settings, "diffusion"); if (!diffusion) { int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Fluid Diffusion", .key = "diffusion", .regex = "\\.[0-9]+", - .preferred = SETTINGS_STR(DEFAULT_DIFFUSION), + .preferred = TIL_SETTINGS_STR(DEFAULT_DIFFUSION), .values = values, .annotations = NULL }, next_setting); @@ -345,7 +345,7 @@ static int flui2d_setup(const settings_t *settings, setting_desc_t **next_settin } -rototiller_module_t flui2d_module = { +til_module_t flui2d_module = { .create_context = flui2d_create_context, .destroy_context = flui2d_destroy_context, .prepare_frame = flui2d_prepare_frame, diff --git a/src/modules/julia/julia.c b/src/modules/julia/julia.c index 61515bd..5e7a350 100644 --- a/src/modules/julia/julia.c +++ b/src/modules/julia/julia.c @@ -3,8 +3,8 @@ #include #include -#include "fb.h" -#include "rototiller.h" +#include "til.h" +#include "til_fb.h" /* Copyright (C) 2017 Vito Caputo */ @@ -102,16 +102,16 @@ static inline unsigned julia_iter(float real, float imag, float creal, float cim } -static int julia_fragmenter(void *context, const fb_fragment_t *fragment, unsigned number, fb_fragment_t *res_fragment) +static int julia_fragmenter(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment) { julia_context_t *ctxt = context; - return fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); + return til_fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); } /* Prepare a frame for concurrent drawing of fragment using multiple fragments */ -static void julia_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void julia_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { julia_context_t *ctxt = context; @@ -139,7 +139,7 @@ static void julia_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, /* Draw a morphing Julia set */ -static void julia_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void julia_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { julia_context_t *ctxt = context; unsigned x, y; @@ -160,7 +160,7 @@ static void julia_render_fragment(void *context, unsigned ticks, unsigned cpu, f } -rototiller_module_t julia_module = { +til_module_t julia_module = { .create_context = julia_create_context, .destroy_context = julia_destroy_context, .prepare_frame = julia_prepare_frame, diff --git a/src/modules/meta2d/meta2d.c b/src/modules/meta2d/meta2d.c index 56f9b25..18af219 100644 --- a/src/modules/meta2d/meta2d.c +++ b/src/modules/meta2d/meta2d.c @@ -19,9 +19,10 @@ #include #include +#include "til.h" +#include "til_fb.h" + #include "din/din.h" -#include "fb.h" -#include "rototiller.h" #include "v2f.h" #include "v3f.h" @@ -100,15 +101,15 @@ static void meta2d_destroy_context(void *context) } -static int meta2d_fragmenter(void *context, const fb_fragment_t *fragment, unsigned number, fb_fragment_t *res_fragment) +static int meta2d_fragmenter(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment) { meta2d_context_t *ctxt = context; - return fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); + return til_fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); } -static void meta2d_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void meta2d_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { meta2d_context_t *ctxt = context; @@ -185,7 +186,7 @@ static void meta2d_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, } -static void meta2d_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void meta2d_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { meta2d_context_t *ctxt = context; float xf = 2.f / (float)fragment->frame_width; @@ -217,13 +218,13 @@ static void meta2d_render_fragment(void *context, unsigned ticks, unsigned cpu, color = (v3f_t){}; pixel = color_to_uint32(color); - fb_fragment_put_pixel_unchecked(fragment, x, y, pixel); + til_fb_fragment_put_pixel_unchecked(fragment, x, y, pixel); } } } -rototiller_module_t meta2d_module = { +til_module_t meta2d_module = { .create_context = meta2d_create_context, .destroy_context = meta2d_destroy_context, .prepare_frame = meta2d_prepare_frame, diff --git a/src/modules/montage/montage.c b/src/modules/montage/montage.c index f791ac1..2af0457 100644 --- a/src/modules/montage/montage.c +++ b/src/modules/montage/montage.c @@ -2,15 +2,14 @@ #include #include -#include "fb.h" -#include "rototiller.h" -#include "settings.h" -#include "util.h" +#include "til.h" +#include "til_fb.h" +#include "til_util.h" /* Copyright (C) 2019 - Vito Caputo */ typedef struct montage_context_t { - const rototiller_module_t **modules; + const til_module_t **modules; void **contexts; size_t n_modules; unsigned n_cpus; @@ -19,11 +18,11 @@ typedef struct montage_context_t { static void setup_next_module(montage_context_t *ctxt); static void * montage_create_context(unsigned ticks, unsigned num_cpus); static void montage_destroy_context(void *context); -static void montage_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter); -static void montage_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment); +static void montage_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter); +static void montage_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment); -rototiller_module_t montage_module = { +til_module_t montage_module = { .create_context = montage_create_context, .destroy_context = montage_destroy_context, .prepare_frame = montage_prepare_frame, @@ -35,28 +34,28 @@ rototiller_module_t montage_module = { static void * montage_create_context(unsigned ticks, unsigned num_cpus) { - const rototiller_module_t **modules, *rtv_module, *compose_module; - size_t n_modules; - montage_context_t *ctxt; + const til_module_t **modules, *rtv_module, *compose_module; + size_t n_modules; + montage_context_t *ctxt; ctxt = calloc(1, sizeof(montage_context_t)); if (!ctxt) return NULL; - rototiller_get_modules(&modules, &n_modules); + til_get_modules(&modules, &n_modules); - ctxt->modules = calloc(n_modules, sizeof(rototiller_module_t *)); + ctxt->modules = calloc(n_modules, sizeof(til_module_t *)); if (!ctxt->modules) { free(ctxt); return NULL; } - rtv_module = rototiller_lookup_module("rtv"); - compose_module = rototiller_lookup_module("compose"); + rtv_module = til_lookup_module("rtv"); + compose_module = til_lookup_module("compose"); for (size_t i = 0; i < n_modules; i++) { - const rototiller_module_t *module = modules[i]; + const til_module_t *module = modules[i]; if (module == &montage_module || /* prevents recursion */ module == rtv_module || /* also prevents recursion, rtv can run montage */ @@ -88,7 +87,7 @@ static void * montage_create_context(unsigned ticks, unsigned num_cpus) } for (size_t i = 0; i < ctxt->n_modules; i++) { - const rototiller_module_t *module = ctxt->modules[i]; + const til_module_t *module = ctxt->modules[i]; if (module->create_context) /* FIXME errors */ ctxt->contexts[i] = module->create_context(ticks, 1); @@ -103,7 +102,7 @@ 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]; + const til_module_t *module = ctxt->modules[i]; if (!ctxt->contexts[i]) continue; @@ -118,8 +117,8 @@ static void montage_destroy_context(void *context) -/* this is a hacked up derivative of fb_fragment_tile_single() */ -static int montage_fragment_tile(const fb_fragment_t *fragment, unsigned tile_width, unsigned tile_height, unsigned number, fb_fragment_t *res_fragment) +/* this is a hacked up derivative of til_fb_fragment_tile_single() */ +static int montage_fragment_tile(const til_fb_fragment_t *fragment, unsigned tile_width, unsigned tile_height, unsigned number, til_fb_fragment_t *res_fragment) { unsigned w = fragment->width / tile_width, h = fragment->height / tile_height; unsigned x, y, xoff, yoff; @@ -166,7 +165,7 @@ static int montage_fragment_tile(const fb_fragment_t *fragment, unsigned tile_wi * 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) +static int montage_fragmenter(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment) { montage_context_t *ctxt = context; float root = sqrtf(ctxt->n_modules); @@ -186,7 +185,7 @@ static int montage_fragmenter(void *context, const fb_fragment_t *fragment, unsi -static void montage_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void montage_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { montage_context_t *ctxt = context; @@ -194,13 +193,13 @@ static void montage_prepare_frame(void *context, unsigned ticks, unsigned n_cpus } -static void montage_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void montage_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { - montage_context_t *ctxt = context; - const rototiller_module_t *module = ctxt->modules[fragment->number]; + montage_context_t *ctxt = context; + const til_module_t *module = ctxt->modules[fragment->number]; if (fragment->number >= ctxt->n_modules) { - fb_fragment_zero(fragment); + til_fb_fragment_zero(fragment); return; } @@ -212,7 +211,7 @@ static void montage_render_fragment(void *context, unsigned ticks, unsigned cpu, * fashion for now. FIXME TODO: move this into rototiller.c */ if (module->prepare_frame) { - rototiller_fragmenter_t unused; + til_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 diff --git a/src/modules/pixbounce/pixbounce.c b/src/modules/pixbounce/pixbounce.c index 893016f..ff397be 100644 --- a/src/modules/pixbounce/pixbounce.c +++ b/src/modules/pixbounce/pixbounce.c @@ -2,8 +2,8 @@ #include #include +#include "til.h" #include "draw.h" -#include "rototiller.h" /* Copyright (C) 2018-19 Philip J. Freeman */ @@ -135,7 +135,7 @@ static void pixbounce_destroy_context(void *context) free(context); } -static void pixbounce_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void pixbounce_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { pixbounce_context_t *ctxt = context; @@ -143,7 +143,7 @@ static void pixbounce_render_fragment(void *context, unsigned ticks, unsigned cp int width = fragment->width, height = fragment->height; /* blank the frame */ - fb_fragment_zero(fragment); + til_fb_fragment_zero(fragment); /* check for very small fragment */ if(pix_width*2>width||pix_height*2>height) @@ -164,7 +164,7 @@ static void pixbounce_render_fragment(void *context, unsigned ticks, unsigned cp for(int cursor_x=0; cursor_x < pix_width*multiplier; cursor_x++) { int pix_offset = ((cursor_y/multiplier)*pix_width) + (cursor_x/multiplier); if(pix_map[ctxt->pix_num][pix_offset] == 0) continue; - fb_fragment_put_pixel_unchecked( + til_fb_fragment_put_pixel_unchecked( fragment, ctxt->x+cursor_x, ctxt->y+cursor_y, makergb(0xFF, 0xFF, 0xFF, 1) ); @@ -192,7 +192,7 @@ static void pixbounce_render_fragment(void *context, unsigned ticks, unsigned cp ctxt->y = ctxt->y+ctxt->y_dir; } -rototiller_module_t pixbounce_module = { +til_module_t pixbounce_module = { .create_context = pixbounce_create_context, .destroy_context = pixbounce_destroy_context, .render_fragment = pixbounce_render_fragment, diff --git a/src/modules/plasma/plasma.c b/src/modules/plasma/plasma.c index 23d7ef2..b970205 100644 --- a/src/modules/plasma/plasma.c +++ b/src/modules/plasma/plasma.c @@ -3,8 +3,8 @@ #include #include -#include "fb.h" -#include "rototiller.h" +#include "til.h" +#include "til_fb.h" /* Copyright (C) 2017 Vito Caputo */ @@ -72,16 +72,16 @@ static void plasma_destroy_context(void *context) } -static int plasma_fragmenter(void *context, const fb_fragment_t *fragment, unsigned number, fb_fragment_t *res_fragment) +static int plasma_fragmenter(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment) { plasma_context_t *ctxt = context; - return fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); + return til_fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); } /* Prepare a frame for concurrent drawing of fragment using multiple fragments */ -static void plasma_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void plasma_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { plasma_context_t *ctxt = context; @@ -92,7 +92,7 @@ static void plasma_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, /* Draw a plasma effect */ -static void plasma_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void plasma_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { plasma_context_t *ctxt = context; int xstep = PLASMA_WIDTH / fragment->frame_width; @@ -161,7 +161,7 @@ static void plasma_render_fragment(void *context, unsigned ticks, unsigned cpu, } -rototiller_module_t plasma_module = { +til_module_t plasma_module = { .create_context = plasma_create_context, .destroy_context = plasma_destroy_context, .prepare_frame = plasma_prepare_frame, diff --git a/src/modules/plato/plato.c b/src/modules/plato/plato.c index 8f0810e..d5c1357 100644 --- a/src/modules/plato/plato.c +++ b/src/modules/plato/plato.c @@ -44,8 +44,8 @@ #include #include -#include "fb.h" -#include "rototiller.h" +#include "til.h" +#include "til_fb.h" typedef struct plato_context_t { @@ -546,7 +546,7 @@ static inline uint32_t color_to_uint32(v3f_t color) { } -static void draw_line(fb_fragment_t *fragment, int x1, int y1, int x2, int y2) +static void draw_line(til_fb_fragment_t *fragment, int x1, int y1, int x2, int y2) { int x_delta = x2 - x1; int y_delta = y2 - y1; @@ -564,7 +564,7 @@ static void draw_line(fb_fragment_t *fragment, int x1, int y1, int x2, int y2) minor -= x_delta; } - fb_fragment_put_pixel_checked(fragment, x1, y1, 0xffffffff); + til_fb_fragment_put_pixel_checked(fragment, x1, y1, 0xffffffff); } } else { /* Y-major */ @@ -574,14 +574,14 @@ static void draw_line(fb_fragment_t *fragment, int x1, int y1, int x2, int y2) minor -= y_delta; } - fb_fragment_put_pixel_checked(fragment, x1, y1, 0xffffffff); + til_fb_fragment_put_pixel_checked(fragment, x1, y1, 0xffffffff); } } } #define ZCONST 3.f -static void draw_polyhedron(const polyhedron_t *polyhedron, m4f_t *transform, fb_fragment_t *fragment) +static void draw_polyhedron(const polyhedron_t *polyhedron, m4f_t *transform, til_fb_fragment_t *fragment) { unsigned n_faces = polyhedron->edge_cnt - polyhedron->vertex_cnt + 2; // https://en.wikipedia.org/wiki/Euler%27s_polyhedron_formula unsigned n_verts_per_face = polyhedron->n_vertices / n_faces; @@ -631,12 +631,12 @@ static void plato_destroy_context(void *context) } -static void plato_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void plato_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { plato_context_t *ctxt = context; ctxt->r += .015f; - fb_fragment_zero(fragment); + til_fb_fragment_zero(fragment); for (int i = 0; i < sizeof(polyhedra) / sizeof(*polyhedra); i++) { m4f_t transform; @@ -667,7 +667,7 @@ static void plato_render_fragment(void *context, unsigned ticks, unsigned cpu, f } -rototiller_module_t plato_module = { +til_module_t plato_module = { .create_context = plato_create_context, .destroy_context = plato_destroy_context, .render_fragment = plato_render_fragment, diff --git a/src/modules/ray/ray.c b/src/modules/ray/ray.c index 636e834..07e1f99 100644 --- a/src/modules/ray/ray.c +++ b/src/modules/ray/ray.c @@ -2,9 +2,9 @@ #include #include -#include "fb.h" -#include "rototiller.h" -#include "util.h" +#include "til.h" +#include "til_fb.h" +#include "til_util.h" #include "ray/ray_camera.h" #include "ray/ray_object.h" @@ -142,14 +142,14 @@ static void ray_destroy_context(void *context) } -static int ray_fragmenter(void *context, const fb_fragment_t *fragment, unsigned number, fb_fragment_t *res_fragment) +static int ray_fragmenter(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment) { - return fb_fragment_tile_single(fragment, 64, number, res_fragment); + return til_fb_fragment_tile_single(fragment, 64, number, res_fragment); } /* prepare a frame for concurrent rendering */ -static void ray_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void ray_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { ray_context_t *ctxt = context; @@ -181,7 +181,7 @@ static void ray_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb /* ray trace a simple scene into the fragment */ -static void ray_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void ray_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { ray_context_t *ctxt = context; @@ -189,7 +189,7 @@ static void ray_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_ } -static void ray_finish_frame(void *context, unsigned ticks, fb_fragment_t *fragment) +static void ray_finish_frame(void *context, unsigned ticks, til_fb_fragment_t *fragment) { ray_context_t *ctxt = context; @@ -197,7 +197,7 @@ static void ray_finish_frame(void *context, unsigned ticks, fb_fragment_t *fragm } -rototiller_module_t ray_module = { +til_module_t ray_module = { .create_context = ray_create_context, .destroy_context = ray_destroy_context, .prepare_frame = ray_prepare_frame, diff --git a/src/modules/roto/roto.c b/src/modules/roto/roto.c index c72301b..0ccb1e2 100644 --- a/src/modules/roto/roto.c +++ b/src/modules/roto/roto.c @@ -3,8 +3,8 @@ #include #include -#include "fb.h" -#include "rototiller.h" +#include "til.h" +#include "til_fb.h" /* Copyright (C) 2016 Vito Caputo */ @@ -169,16 +169,16 @@ static void init_roto(uint8_t texture[256][256], int32_t *costab, int32_t *sinta } -static int roto_fragmenter(void *context, const fb_fragment_t *fragment, unsigned number, fb_fragment_t *res_fragment) +static int roto_fragmenter(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment) { roto_context_t *ctxt = context; - return fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); + return til_fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); } /* prepare a frame for concurrent rendering */ -static void roto_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void roto_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { roto_context_t *ctxt = context; static int initialized; @@ -199,7 +199,7 @@ static void roto_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, f /* Draw a rotating checkered 256x256 texture into fragment. */ -static void roto_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void roto_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { roto_context_t *ctxt = context; int y_cos_r, y_sin_r, x_cos_r, x_sin_r, x_cos_r_init, x_sin_r_init, cos_r, sin_r; @@ -248,7 +248,7 @@ static void roto_render_fragment(void *context, unsigned ticks, unsigned cpu, fb } -rototiller_module_t roto_module = { +til_module_t roto_module = { .create_context = roto_create_context, .destroy_context = roto_destroy_context, .prepare_frame = roto_prepare_frame, diff --git a/src/modules/rtv/rtv.c b/src/modules/rtv/rtv.c index 7731603..a517e8c 100644 --- a/src/modules/rtv/rtv.c +++ b/src/modules/rtv/rtv.c @@ -1,11 +1,12 @@ #include #include -#include "fb.h" -#include "rototiller.h" -#include "settings.h" +#include "til.h" +#include "til_fb.h" +#include "til_settings.h" +#include "til_util.h" + #include "txt/txt.h" -#include "util.h" /* Copyright (C) 2019 - Vito Caputo */ @@ -21,33 +22,33 @@ #define RTV_CONTEXT_DURATION_SECS 60 typedef struct rtv_channel_t { - const rototiller_module_t *module; - void *module_ctxt; - time_t last_on_time, cumulative_time; - char *settings; - txt_t *caption; - unsigned order; + const til_module_t *module; + void *module_ctxt; + time_t last_on_time, cumulative_time; + char *settings; + txt_t *caption; + unsigned order; } rtv_channel_t; typedef struct rtv_context_t { - unsigned n_cpus; + unsigned n_cpus; - time_t next_switch, next_hide_caption; - rtv_channel_t *channel, *last_channel; - txt_t *caption; + time_t next_switch, next_hide_caption; + rtv_channel_t *channel, *last_channel; + txt_t *caption; - rtv_channel_t snow_channel; + rtv_channel_t snow_channel; - size_t n_channels; - rtv_channel_t channels[]; + size_t n_channels; + rtv_channel_t channels[]; } rtv_context_t; static void setup_next_channel(rtv_context_t *ctxt, unsigned ticks); static void * rtv_create_context(unsigned ticks, unsigned num_cpus); static void rtv_destroy_context(void *context); -static void rtv_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter); -static void rtv_finish_frame(void *context, unsigned ticks, fb_fragment_t *fragment); -static int rtv_setup(const settings_t *settings, setting_desc_t **next_setting); +static void rtv_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter); +static void rtv_finish_frame(void *context, unsigned ticks, til_fb_fragment_t *fragment); +static int rtv_setup(const til_settings_t *settings, til_setting_desc_t **next_setting); static unsigned rtv_duration = RTV_DURATION_SECS; static unsigned rtv_context_duration = RTV_CONTEXT_DURATION_SECS; @@ -57,7 +58,7 @@ static char **rtv_channels; static char *rtv_snow_module; -rototiller_module_t rtv_module = { +til_module_t rtv_module = { .create_context = rtv_create_context, .destroy_context = rtv_destroy_context, .prepare_frame = rtv_prepare_frame, @@ -91,16 +92,16 @@ static void randomize_channels(rtv_context_t *ctxt) } -static char * randomize_module_setup(const rototiller_module_t *module) +static char * randomize_module_setup(const til_module_t *module) { - settings_t *settings; - setting_desc_t *desc; - char *arg; + til_settings_t *settings; + til_setting_desc_t *desc; + char *arg; if (!module->setup) return NULL; - settings = settings_new(NULL); + settings = til_settings_new(NULL); if (!settings) return NULL; @@ -109,7 +110,7 @@ static char * randomize_module_setup(const rototiller_module_t *module) char *value; value = desc->random(); - settings_add_value(settings, desc->key, value); + til_settings_add_value(settings, desc->key, value); free(value); } else if (desc->values) { int n; @@ -118,16 +119,16 @@ static char * randomize_module_setup(const rototiller_module_t *module) n = rand() % n; - settings_add_value(settings, desc->key, desc->values[n]); + til_settings_add_value(settings, desc->key, desc->values[n]); } else { - settings_add_value(settings, desc->key, desc->preferred); + til_settings_add_value(settings, desc->key, desc->preferred); } - setting_desc_free(desc); + til_setting_desc_free(desc); } - arg = settings_as_arg(settings); - settings_free(settings); + arg = til_settings_as_arg(settings); + til_settings_free(settings); return arg; } @@ -209,7 +210,7 @@ static void setup_next_channel(rtv_context_t *ctxt, unsigned ticks) } -static int rtv_should_skip_module(const rtv_context_t *ctxt, const rototiller_module_t *module) +static int rtv_should_skip_module(const rtv_context_t *ctxt, const til_module_t *module) { if (module == &rtv_module || module == ctxt->snow_channel.module) @@ -229,12 +230,12 @@ static int rtv_should_skip_module(const rtv_context_t *ctxt, const rototiller_mo static void * rtv_create_context(unsigned ticks, unsigned num_cpus) { - rtv_context_t *ctxt; - const rototiller_module_t **modules; - size_t n_modules; - static rototiller_module_t none_module = {}; + rtv_context_t *ctxt; + const til_module_t **modules; + size_t n_modules; + static til_module_t none_module = {}; - rototiller_get_modules(&modules, &n_modules); + til_get_modules(&modules, &n_modules); ctxt = calloc(1, sizeof(rtv_context_t) + n_modules * sizeof(rtv_channel_t)); if (!ctxt) @@ -244,7 +245,7 @@ static void * rtv_create_context(unsigned ticks, unsigned num_cpus) ctxt->snow_channel.module = &none_module; if (rtv_snow_module) { - ctxt->snow_channel.module = rototiller_lookup_module(rtv_snow_module); + ctxt->snow_channel.module = til_lookup_module(rtv_snow_module); if (ctxt->snow_channel.module->create_context) ctxt->snow_channel.module_ctxt = ctxt->snow_channel.module->create_context(ticks, ctxt->n_cpus); } @@ -268,7 +269,7 @@ static void rtv_destroy_context(void *context) } -static void rtv_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void rtv_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { rtv_context_t *ctxt = context; time_t now = time(NULL); @@ -284,13 +285,13 @@ static void rtv_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb */ if (!ctxt->channel->module->render_fragment && !ctxt->channel->module->prepare_frame) - fb_fragment_zero(fragment); + til_fb_fragment_zero(fragment); else - rototiller_module_render(ctxt->channel->module, ctxt->channel->module_ctxt, ticks, fragment); + til_module_render(ctxt->channel->module, ctxt->channel->module_ctxt, ticks, fragment); } -static void rtv_finish_frame(void *context, unsigned ticks, fb_fragment_t *fragment) +static void rtv_finish_frame(void *context, unsigned ticks, til_fb_fragment_t *fragment) { rtv_context_t *ctxt = context; @@ -312,7 +313,7 @@ static void rtv_finish_frame(void *context, unsigned ticks, fb_fragment_t *fragm } -static int rtv_setup(const settings_t *settings, setting_desc_t **next_setting) +static int rtv_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) { const char *duration; const char *context_duration; @@ -321,11 +322,11 @@ static int rtv_setup(const settings_t *settings, setting_desc_t **next_setting) const char *channels; const char *snow_module; - channels = settings_get_value(settings, "channels"); + channels = til_settings_get_value(settings, "channels"); if (!channels) { int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Colon-Separated List Of Channel Modules", .key = "channels", .preferred = "all", @@ -337,15 +338,15 @@ static int rtv_setup(const settings_t *settings, setting_desc_t **next_setting) return 1; } - duration = settings_get_value(settings, "duration"); + duration = til_settings_get_value(settings, "duration"); if (!duration) { int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Channel Duration In Seconds", .key = "duration", .regex = "\\.[0-9]+", - .preferred = SETTINGS_STR(RTV_DURATION_SECS), + .preferred = TIL_SETTINGS_STR(RTV_DURATION_SECS), .annotations = NULL }, next_setting); if (r < 0) @@ -354,15 +355,15 @@ static int rtv_setup(const settings_t *settings, setting_desc_t **next_setting) return 1; } - context_duration = settings_get_value(settings, "context_duration"); + context_duration = til_settings_get_value(settings, "context_duration"); if (!context_duration) { int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Context Duration In Seconds", .key = "context_duration", .regex = "\\.[0-9]+", - .preferred = SETTINGS_STR(RTV_CONTEXT_DURATION_SECS), + .preferred = TIL_SETTINGS_STR(RTV_CONTEXT_DURATION_SECS), .annotations = NULL }, next_setting); if (r < 0) @@ -371,15 +372,15 @@ static int rtv_setup(const settings_t *settings, setting_desc_t **next_setting) return 1; } - caption_duration = settings_get_value(settings, "caption_duration"); + caption_duration = til_settings_get_value(settings, "caption_duration"); if (!caption_duration) { int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Caption Duration In Seconds", .key = "caption_duration", .regex = "\\.[0-9]+", - .preferred = SETTINGS_STR(RTV_CAPTION_DURATION_SECS), + .preferred = TIL_SETTINGS_STR(RTV_CAPTION_DURATION_SECS), .annotations = NULL }, next_setting); if (r < 0) @@ -388,15 +389,15 @@ static int rtv_setup(const settings_t *settings, setting_desc_t **next_setting) return 1; } - snow_duration = settings_get_value(settings, "snow_duration"); + snow_duration = til_settings_get_value(settings, "snow_duration"); if (!snow_duration) { int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Snow On Channel Switch Duration In Seconds", .key = "snow_duration", .regex = "\\.[0-9]+", - .preferred = SETTINGS_STR(RTV_SNOW_DURATION_SECS), + .preferred = TIL_SETTINGS_STR(RTV_SNOW_DURATION_SECS), .annotations = NULL }, next_setting); if (r < 0) @@ -405,11 +406,11 @@ static int rtv_setup(const settings_t *settings, setting_desc_t **next_setting) return 1; } - snow_module = settings_get_value(settings, "snow_module"); + snow_module = til_settings_get_value(settings, "snow_module"); if (!snow_module) { int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Module To Use For Snow (\"none\" To Blank)", .key = "snow_module", .preferred = "snow", @@ -423,12 +424,12 @@ static int rtv_setup(const settings_t *settings, setting_desc_t **next_setting) /* turn channels colon-separated list into a null-terminated array of strings */ if (strcmp(channels, "all")) { - const rototiller_module_t **modules; - size_t n_modules; - char *tokchannels, *channel; - int n = 2; + const til_module_t **modules; + size_t n_modules; + char *tokchannels, *channel; + int n = 2; - rototiller_get_modules(&modules, &n_modules); + til_get_modules(&modules, &n_modules); tokchannels = strdup(channels); if (!tokchannels) diff --git a/src/modules/snow/snow.c b/src/modules/snow/snow.c index d1f3758..5c753b9 100644 --- a/src/modules/snow/snow.c +++ b/src/modules/snow/snow.c @@ -2,8 +2,8 @@ #include #include -#include "fb.h" -#include "rototiller.h" +#include "til.h" +#include "til_fb.h" /* Copyright (C) 2019 - Vito Caputo */ @@ -43,21 +43,21 @@ static void snow_destroy_context(void *context) } -static int snow_fragmenter(void *context, const fb_fragment_t *fragment, unsigned number, fb_fragment_t *res_fragment) +static int snow_fragmenter(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment) { snow_context_t *ctxt = context; - return fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); + return til_fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); } -static void snow_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void snow_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { *res_fragmenter = snow_fragmenter; } -static void snow_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void snow_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { snow_context_t *ctxt = context; int *seed = &ctxt->seeds[cpu].seed; @@ -70,13 +70,13 @@ static void snow_render_fragment(void *context, unsigned ticks, unsigned cpu, fb uint32_t pixel = rand_r(seed) % 256; #endif - fb_fragment_put_pixel_unchecked(fragment, x, y, pixel << 16 | pixel << 8 | pixel); + til_fb_fragment_put_pixel_unchecked(fragment, x, y, pixel << 16 | pixel << 8 | pixel); } } } -rototiller_module_t snow_module = { +til_module_t snow_module = { .create_context = snow_create_context, .destroy_context = snow_destroy_context, .prepare_frame = snow_prepare_frame, diff --git a/src/modules/sparkler/burst.c b/src/modules/sparkler/burst.c index b5ad365..cf35b31 100644 --- a/src/modules/sparkler/burst.c +++ b/src/modules/sparkler/burst.c @@ -43,13 +43,13 @@ static inline void thrust_part(particle_t *burst, particle_t *victim, float dist typedef struct burst_sphere_t { - particles_t *particles; - particle_t *center, *last; - fb_fragment_t *fragment; - float radius_min; - float radius_max; - unsigned trace_matches:1; - unsigned trace_affected:1; + particles_t *particles; + particle_t *center, *last; + til_fb_fragment_t *fragment; + float radius_min; + float radius_max; + unsigned trace_matches:1; + unsigned trace_affected:1; } burst_sphere_t; @@ -94,7 +94,7 @@ static void burst_cb(bsp_t *bsp, list_head_t *occupants, void *_s) } -static particle_status_t burst_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, fb_fragment_t *f) +static particle_status_t burst_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, til_fb_fragment_t *f) { burst_ctxt_t *ctxt = p->ctxt; bsp_t *bsp = particles_bsp(particles); /* XXX see note above about bsp_occupant_t */ diff --git a/src/modules/sparkler/helpers.h b/src/modules/sparkler/helpers.h index 3fd1bda..4c2497e 100644 --- a/src/modules/sparkler/helpers.h +++ b/src/modules/sparkler/helpers.h @@ -3,7 +3,8 @@ #include -#include "fb.h" +#include "til_fb.h" + #include "particle.h" #include "particles.h" @@ -20,9 +21,9 @@ static inline uint32_t makergb(uint32_t r, uint32_t g, uint32_t b, float intensi /* return if the particle should be drawn, and set *longevity to 0 if out of bounds */ -static inline int should_draw_expire_if_oob(particles_t *particles, particle_t *p, int x, int y, fb_fragment_t *f, int *longevity) +static inline int should_draw_expire_if_oob(particles_t *particles, particle_t *p, int x, int y, til_fb_fragment_t *f, int *longevity) { - if (!fb_fragment_contains(f, x, y)) { + if (!til_fb_fragment_contains(f, x, y)) { if (longevity && (x < 0 || x > f->frame_width || y < 0 || y > f->frame_height)) *longevity = 0; /* offscreen */ diff --git a/src/modules/sparkler/particle.h b/src/modules/sparkler/particle.h index a5999ee..6a5bf73 100644 --- a/src/modules/sparkler/particle.h +++ b/src/modules/sparkler/particle.h @@ -1,8 +1,9 @@ #ifndef _PARTICLE_H #define _PARTICLE_H +#include "til_fb.h" + #include "bsp.h" -#include "fb.h" #include "v3f.h" typedef struct particle_props_t { @@ -28,8 +29,8 @@ typedef struct particle_ops_t { unsigned context_size; /* size of the particle context (0 for none) */ int (*init)(particles_t *, const particles_conf_t *, particle_t *); /* initialize the particle, called after allocating context (optional) */ void (*cleanup)(particles_t *, const particles_conf_t *, particle_t *); /* cleanup function, called before freeing context (optional) */ - particle_status_t (*sim)(particles_t *, const particles_conf_t *, particle_t *, fb_fragment_t *); /* simulate the particle for another cycle (required) */ - void (*draw)(particles_t *, const particles_conf_t *, particle_t *, int, int, fb_fragment_t *); /* draw the particle, 3d->2d projection has been done already (optional) */ + particle_status_t (*sim)(particles_t *, const particles_conf_t *, particle_t *, til_fb_fragment_t *); /* simulate the particle for another cycle (required) */ + void (*draw)(particles_t *, const particles_conf_t *, particle_t *, int, int, til_fb_fragment_t *); /* draw the particle, 3d->2d projection has been done already (optional) */ } particle_ops_t; struct particle_t { @@ -68,12 +69,12 @@ static inline void particle_cleanup(particles_t *particles, const particles_conf * example is true, then sim may draw into fragment, and the callers shouldn't zero the fragment between sim and draw but * instead should zero it before sim. It's kind of janky, not a fan. */ -static inline particle_status_t particle_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, fb_fragment_t *f) { +static inline particle_status_t particle_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, til_fb_fragment_t *f) { return p->ops->sim(particles, conf, p, f); } -static inline void particle_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, fb_fragment_t *f) { +static inline void particle_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, til_fb_fragment_t *f) { if (p->ops->draw) { p->ops->draw(particles, conf, p, x, y, f); } diff --git a/src/modules/sparkler/particles.c b/src/modules/sparkler/particles.c index d4677b7..a567cea 100644 --- a/src/modules/sparkler/particles.c +++ b/src/modules/sparkler/particles.c @@ -7,7 +7,7 @@ #include #include -#include "fb.h" +#include "til_fb.h" #include "chunker.h" #include "container.h" @@ -221,7 +221,7 @@ bsp_t * particles_bsp(particles_t *particles) } -static inline void _particles_draw(particles_t *particles, list_head_t *list, fb_fragment_t *fragment) +static inline void _particles_draw(particles_t *particles, list_head_t *list, til_fb_fragment_t *fragment) { float w2 = fragment->frame_width * .5f, h2 = fragment->frame_height * .5f; _particle_t *p; @@ -247,7 +247,7 @@ static inline void _particles_draw(particles_t *particles, list_head_t *list, fb /* TODO: maybe polish up and move into fb.c? */ -static void draw_line(fb_fragment_t *fragment, int x1, int y1, int x2, int y2) +static void draw_line(til_fb_fragment_t *fragment, int x1, int y1, int x2, int y2) { int x_delta = x2 - x1; int y_delta = y2 - y1; @@ -265,7 +265,7 @@ static void draw_line(fb_fragment_t *fragment, int x1, int y1, int x2, int y2) minor -= x_delta; } - fb_fragment_put_pixel_checked(fragment, x1, y1, 0xffffffff); + til_fb_fragment_put_pixel_checked(fragment, x1, y1, 0xffffffff); } } else { /* Y-major */ @@ -275,13 +275,13 @@ static void draw_line(fb_fragment_t *fragment, int x1, int y1, int x2, int y2) minor -= y_delta; } - fb_fragment_put_pixel_checked(fragment, x1, y1, 0xffffffff); + til_fb_fragment_put_pixel_checked(fragment, x1, y1, 0xffffffff); } } } -static void draw_edge(fb_fragment_t *fragment, const v3f_t *a, const v3f_t *b) +static void draw_edge(til_fb_fragment_t *fragment, const v3f_t *a, const v3f_t *b) { float w2 = fragment->frame_width * .5f, h2 = fragment->frame_height * .5f; int x1, y1, x2, y2; @@ -296,7 +296,7 @@ static void draw_edge(fb_fragment_t *fragment, const v3f_t *a, const v3f_t *b) } -static void draw_bv(fb_fragment_t *fragment, const v3f_t *bv_min, const v3f_t *bv_max) +static void draw_bv(til_fb_fragment_t *fragment, const v3f_t *bv_min, const v3f_t *bv_max) { draw_edge(fragment, &(v3f_t){bv_min->x, bv_max->y, bv_min->z}, @@ -339,8 +339,8 @@ static void draw_bv(fb_fragment_t *fragment, const v3f_t *bv_min, const v3f_t *b /* something to encapsulate these pointers for passing through as one to draw_leaf() */ typedef struct draw_leafs_t { - particles_t *particles; - fb_fragment_t *fragment; + particles_t *particles; + til_fb_fragment_t *fragment; } draw_leafs_t; @@ -360,7 +360,7 @@ static void draw_leaf(const bsp_t *bsp, const list_head_t *occupants, unsigned d /* draw all of the particles, currently called in heirarchical order */ -void particles_draw(particles_t *particles, fb_fragment_t *fragment) +void particles_draw(particles_t *particles, til_fb_fragment_t *fragment) { draw_leafs_t draw = { .particles = particles, .fragment = fragment }; @@ -373,7 +373,7 @@ void particles_draw(particles_t *particles, fb_fragment_t *fragment) } -static inline particle_status_t _particles_sim(particles_t *particles, list_head_t *list, fb_fragment_t *fragment) +static inline particle_status_t _particles_sim(particles_t *particles, list_head_t *list, til_fb_fragment_t *fragment) { particle_status_t ret = PARTICLE_DEAD, s; _particle_t *p, *_p; @@ -400,7 +400,7 @@ static inline particle_status_t _particles_sim(particles_t *particles, list_head /* simulate the particles, call the sim method of every particle in the heirarchy, this is what makes the particles dynamic */ /* if any paticle is still living, we return PARTICLE_ALIVE, to inform the caller when everything's dead */ -particle_status_t particles_sim(particles_t *particles, fb_fragment_t *fragment) +particle_status_t particles_sim(particles_t *particles, til_fb_fragment_t *fragment) { assert(particles); @@ -480,7 +480,7 @@ void particles_age(particles_t *particles) /* draw a line expressed in world-space positions a to b into fragment, this is intended for * instrumentation/overlay debugging type purposes... */ -void particles_draw_line(particles_t *particles, const v3f_t *a, const v3f_t *b, fb_fragment_t *fragment) +void particles_draw_line(particles_t *particles, const v3f_t *a, const v3f_t *b, til_fb_fragment_t *fragment) { float w2 = fragment->frame_width * .5f, h2 = fragment->frame_height * .5f; int x1, y1, x2, y2; diff --git a/src/modules/sparkler/particles.h b/src/modules/sparkler/particles.h index 9d6e3af..1cb737f 100644 --- a/src/modules/sparkler/particles.h +++ b/src/modules/sparkler/particles.h @@ -1,8 +1,9 @@ #ifndef _PARTICLES_H #define _PARTICLES_H +#include "til_fb.h" + #include "bsp.h" -#include "fb.h" #include "list.h" #include "particle.h" @@ -17,14 +18,14 @@ typedef struct particles_t particles_t; typedef struct v3f_t v3f_t; particles_t * particles_new(const particles_conf_t *conf); -void particles_draw(particles_t *particles, fb_fragment_t *fragment); -particle_status_t particles_sim(particles_t *particles, fb_fragment_t *fragment); +void particles_draw(particles_t *particles, til_fb_fragment_t *fragment); +particle_status_t particles_sim(particles_t *particles, til_fb_fragment_t *fragment); void particles_age(particles_t *particles); void particles_free(particles_t *particles); int particles_add_particle(particles_t *particles, particle_props_t *props, particle_ops_t *ops); void particles_spawn_particle(particles_t *particles, particle_t *parent, particle_props_t *props, particle_ops_t *ops); void particles_add_particles(particles_t *particles, particle_props_t *props, particle_ops_t *ops, int num); bsp_t * particles_bsp(particles_t *particles); -void particles_draw_line(particles_t *particles, const v3f_t *a, const v3f_t *b, fb_fragment_t *fragment); +void particles_draw_line(particles_t *particles, const v3f_t *a, const v3f_t *b, til_fb_fragment_t *fragment); #endif diff --git a/src/modules/sparkler/rocket.c b/src/modules/sparkler/rocket.c index 50e1ff5..3885304 100644 --- a/src/modules/sparkler/rocket.c +++ b/src/modules/sparkler/rocket.c @@ -1,6 +1,7 @@ #include -#include "fb.h" +#include "til_fb.h" + #include "helpers.h" #include "particle.h" #include "particles.h" @@ -54,7 +55,7 @@ static int rocket_init(particles_t *particles, const particles_conf_t *conf, par } -static particle_status_t rocket_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, fb_fragment_t *f) +static particle_status_t rocket_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, til_fb_fragment_t *f) { rocket_ctxt_t *ctxt = p->ctxt; int i, n_sparks; @@ -120,7 +121,7 @@ static particle_status_t rocket_sim(particles_t *particles, const particles_conf } -static void rocket_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, fb_fragment_t *f) +static void rocket_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, til_fb_fragment_t *f) { rocket_ctxt_t *ctxt = p->ctxt; @@ -128,7 +129,7 @@ static void rocket_draw(particles_t *particles, const particles_conf_t *conf, pa /* kill off parts that wander off screen */ return; - fb_fragment_put_pixel_unchecked(f, x, y, 0xff0000); + til_fb_fragment_put_pixel_unchecked(f, x, y, 0xff0000); } diff --git a/src/modules/sparkler/simple.c b/src/modules/sparkler/simple.c index 8db15b1..14c5d49 100644 --- a/src/modules/sparkler/simple.c +++ b/src/modules/sparkler/simple.c @@ -1,6 +1,7 @@ #include -#include "fb.h" +#include "til_fb.h" + #include "helpers.h" #include "particle.h" #include "particles.h" @@ -54,7 +55,7 @@ static int simple_init(particles_t *particles, const particles_conf_t *conf, par } -static particle_status_t simple_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, fb_fragment_t *f) +static particle_status_t simple_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, til_fb_fragment_t *f) { simple_ctxt_t *ctxt = p->ctxt; @@ -95,7 +96,7 @@ static particle_status_t simple_sim(particles_t *particles, const particles_conf } -static void simple_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, fb_fragment_t *f) +static void simple_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, til_fb_fragment_t *f) { simple_ctxt_t *ctxt = p->ctxt; @@ -103,7 +104,7 @@ static void simple_draw(particles_t *particles, const particles_conf_t *conf, pa /* immediately kill off stars that wander off screen */ return; - fb_fragment_put_pixel_unchecked(f, x, y, makergb(0xff, 0xff, 0xff, ((float)ctxt->longevity / ctxt->lifetime))); + til_fb_fragment_put_pixel_unchecked(f, x, y, makergb(0xff, 0xff, 0xff, ((float)ctxt->longevity / ctxt->lifetime))); } diff --git a/src/modules/sparkler/spark.c b/src/modules/sparkler/spark.c index c432bf5..8eff728 100644 --- a/src/modules/sparkler/spark.c +++ b/src/modules/sparkler/spark.c @@ -1,6 +1,7 @@ #include -#include "fb.h" +#include "til_fb.h" + #include "helpers.h" #include "particle.h" #include "particles.h" @@ -32,7 +33,7 @@ static int spark_init(particles_t *particles, const particles_conf_t *conf, part } -static particle_status_t spark_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, fb_fragment_t *f) +static particle_status_t spark_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, til_fb_fragment_t *f) { spark_ctxt_t *ctxt = p->ctxt; @@ -45,7 +46,7 @@ static particle_status_t spark_sim(particles_t *particles, const particles_conf_ } -static void spark_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, fb_fragment_t *f) +static void spark_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, til_fb_fragment_t *f) { spark_ctxt_t *ctxt = p->ctxt; @@ -53,7 +54,7 @@ static void spark_draw(particles_t *particles, const particles_conf_t *conf, par /* offscreen */ return; - fb_fragment_put_pixel_unchecked(f, x, y, makergb(0xff, 0xa0, 0x20, ((float)ctxt->longevity / ctxt->lifetime))); + til_fb_fragment_put_pixel_unchecked(f, x, y, makergb(0xff, 0xa0, 0x20, ((float)ctxt->longevity / ctxt->lifetime))); } diff --git a/src/modules/sparkler/sparkler.c b/src/modules/sparkler/sparkler.c index b673d0c..8b8681f 100644 --- a/src/modules/sparkler/sparkler.c +++ b/src/modules/sparkler/sparkler.c @@ -4,9 +4,9 @@ #include #include -#include "fb.h" -#include "rototiller.h" -#include "util.h" +#include "til.h" +#include "til_fb.h" +#include "til_util.h" #include "particles.h" @@ -60,14 +60,14 @@ static void sparkler_destroy_context(void *context) } -static int sparkler_fragmenter(void *context, const fb_fragment_t *fragment, unsigned number, fb_fragment_t *res_fragment) +static int sparkler_fragmenter(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment) { sparkler_context_t *ctxt = context; - return fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); + return til_fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); } -static void sparkler_prepare_frame(void *context, unsigned ticks, unsigned ncpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void sparkler_prepare_frame(void *context, unsigned ticks, unsigned ncpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { sparkler_context_t *ctxt = context; @@ -75,7 +75,7 @@ static void sparkler_prepare_frame(void *context, unsigned ticks, unsigned ncpus ctxt->n_cpus = ncpus; if (sparkler_conf.show_bsp_matches) - fb_fragment_zero(fragment); + til_fb_fragment_zero(fragment); particles_sim(ctxt->particles, fragment); particles_add_particles(ctxt->particles, NULL, &simple_ops, INIT_PARTS / 4); @@ -84,19 +84,19 @@ static void sparkler_prepare_frame(void *context, unsigned ticks, unsigned ncpus /* Render a 3D particle system */ -static void sparkler_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void sparkler_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { sparkler_context_t *ctxt = context; if (!sparkler_conf.show_bsp_matches) - fb_fragment_zero(fragment); + til_fb_fragment_zero(fragment); particles_draw(ctxt->particles, fragment); } /* Settings hooks for configurable variables */ -static int sparkler_setup(const settings_t *settings, setting_desc_t **next_setting) +static int sparkler_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) { const char *show_bsp_leafs; const char *show_bsp_matches; @@ -108,11 +108,11 @@ static int sparkler_setup(const settings_t *settings, setting_desc_t **next_sett /* TODO: return -EINVAL on parse errors? */ - show_bsp_leafs = settings_get_value(settings, "show_bsp_leafs"); + show_bsp_leafs = til_settings_get_value(settings, "show_bsp_leafs"); if (!show_bsp_leafs) { int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Show BSP Leaf Node Bounding Boxes", .key = "show_bsp_leafs", .preferred = "off", @@ -129,7 +129,7 @@ static int sparkler_setup(const settings_t *settings, setting_desc_t **next_sett sparkler_conf.show_bsp_leafs = 1; - show_bsp_leafs_min_depth = settings_get_value(settings, "show_bsp_leafs_min_depth"); + show_bsp_leafs_min_depth = til_settings_get_value(settings, "show_bsp_leafs_min_depth"); if (!show_bsp_leafs_min_depth) { const char *depth_values[] = { "0", @@ -141,7 +141,7 @@ static int sparkler_setup(const settings_t *settings, setting_desc_t **next_sett }; int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Show BSP Leaf Node Bounding Boxes Minimum Depth", .key = "show_bsp_leafs_min_depth", .preferred = "8", @@ -158,11 +158,11 @@ static int sparkler_setup(const settings_t *settings, setting_desc_t **next_sett sparkler_conf.show_bsp_leafs = 0; } - show_bsp_matches = settings_get_value(settings, "show_bsp_matches"); + show_bsp_matches = til_settings_get_value(settings, "show_bsp_matches"); if (!show_bsp_matches) { int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Show BSP Search Matches", .key = "show_bsp_matches", .preferred = "off", @@ -182,11 +182,11 @@ static int sparkler_setup(const settings_t *settings, setting_desc_t **next_sett if (!strcasecmp(show_bsp_matches, "on")) { const char *show_bsp_matches_affected_only; - show_bsp_matches_affected_only = settings_get_value(settings, "show_bsp_matches_affected_only"); + show_bsp_matches_affected_only = til_settings_get_value(settings, "show_bsp_matches_affected_only"); if (!show_bsp_matches_affected_only) { int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Show Only Affected BSP Search Matches", .key = "show_bsp_matches_affected_only", .preferred = "off", @@ -208,7 +208,7 @@ static int sparkler_setup(const settings_t *settings, setting_desc_t **next_sett } -rototiller_module_t sparkler_module = { +til_module_t sparkler_module = { .create_context = sparkler_create_context, .destroy_context = sparkler_destroy_context, .prepare_frame = sparkler_prepare_frame, diff --git a/src/modules/sparkler/xplode.c b/src/modules/sparkler/xplode.c index 4d6ee36..931ec83 100644 --- a/src/modules/sparkler/xplode.c +++ b/src/modules/sparkler/xplode.c @@ -1,6 +1,7 @@ #include -#include "fb.h" +#include "til_fb.h" + #include "helpers.h" #include "particle.h" #include "particles.h" @@ -36,7 +37,7 @@ static int xplode_init(particles_t *particles, const particles_conf_t *conf, par } -static particle_status_t xplode_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, fb_fragment_t *f) +static particle_status_t xplode_sim(particles_t *particles, const particles_conf_t *conf, particle_t *p, til_fb_fragment_t *f) { xplode_ctxt_t *ctxt = p->ctxt; @@ -57,7 +58,7 @@ static particle_status_t xplode_sim(particles_t *particles, const particles_conf } -static void xplode_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, fb_fragment_t *f) +static void xplode_draw(particles_t *particles, const particles_conf_t *conf, particle_t *p, int x, int y, til_fb_fragment_t *f) { xplode_ctxt_t *ctxt = p->ctxt; uint32_t color; @@ -71,7 +72,7 @@ static void xplode_draw(particles_t *particles, const particles_conf_t *conf, pa color = makergb(0xff, 0xff, 0x00, ((float)ctxt->longevity / ctxt->lifetime)); } - fb_fragment_put_pixel_unchecked(f, x, y, color); + til_fb_fragment_put_pixel_unchecked(f, x, y, color); } diff --git a/src/modules/spiro/spiro.c b/src/modules/spiro/spiro.c index 6f2af97..ca3086f 100644 --- a/src/modules/spiro/spiro.c +++ b/src/modules/spiro/spiro.c @@ -4,9 +4,10 @@ #include #include +#include "til.h" +#include "til_fb.h" + #include "draw.h" -#include "fb.h" -#include "rototiller.h" /* Copyright (C) 2020 Philip J. Freeman */ @@ -60,7 +61,7 @@ static void spiro_destroy_context(void *context) } -static void spiro_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void spiro_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { spiro_context_t *ctxt = context; @@ -82,7 +83,7 @@ static void spiro_render_fragment(void *context, unsigned ticks, unsigned cpu, f } /* blank the fragment */ - fb_fragment_zero(fragment); + til_fb_fragment_zero(fragment); /* plot one spirograph run */ float l=ctxt->p/ctxt->r; @@ -92,7 +93,7 @@ static void spiro_render_fragment(void *context, unsigned ticks, unsigned cpu, f float my_y=((1.f-k)*sinf(t))-(l*k*sinf(((1.f-k)/k)*t)); int pos_x=display_origin_x+(my_x*display_R); int pos_y=display_origin_y+(my_y*display_R); - fb_fragment_put_pixel_unchecked(fragment, pos_x, pos_y, + til_fb_fragment_put_pixel_unchecked(fragment, pos_x, pos_y, makergb(sinf(M_1_PI*t)*127+128, sinf(M_1_PI*t+(2*M_PI*.333333333333f))*127+128, sinf(M_1_PI*t+(4*M_PI*.333333333333f))*127+128, @@ -101,31 +102,31 @@ static void spiro_render_fragment(void *context, unsigned ticks, unsigned cpu, f #ifdef DEBUG /* plot the origin point */ - fb_fragment_put_pixel_unchecked(fragment, display_origin_x, display_origin_y, + til_fb_fragment_put_pixel_unchecked(fragment, display_origin_x, display_origin_y, makergb(0xFF, 0xFF, 0x00, 1)); /* plot the fixed outer circle C0 */ for(float a=0.f; a<2*M_PI; a+= M_PI_2/display_R) { int pos_x=display_origin_x+(cosf(a)*display_R); int pos_y=display_origin_y+(sinf(a)*display_R); - fb_fragment_put_pixel_unchecked(fragment, pos_x, pos_y, + til_fb_fragment_put_pixel_unchecked(fragment, pos_x, pos_y, makergb(0xFF, 0xFF, 0x00, 1)); } /* plot inner circle Ci */ - fb_fragment_put_pixel_unchecked(fragment, display_origin_x+display_R-(ctxt->r*display_R), + til_fb_fragment_put_pixel_unchecked(fragment, display_origin_x+display_R-(ctxt->r*display_R), display_origin_y, makergb(0xFF, 0xFF, 0x00, 1)); for(float a=0.f; a<2*M_PI; a+= M_PI_2/display_R) { int pos_x=display_origin_x+display_R-(ctxt->r*display_R)+ (cosf(a)*ctxt->r*display_R); int pos_y=display_origin_y+(sinf(a)*ctxt->r*display_R); - fb_fragment_put_pixel_unchecked(fragment, pos_x, pos_y, + til_fb_fragment_put_pixel_unchecked(fragment, pos_x, pos_y, makergb(0xFF, 0xFF, 0x00, 1)); } /* plot p */ - fb_fragment_put_pixel_unchecked(fragment, display_origin_x+display_R-(ctxt->r*display_R)+ + til_fb_fragment_put_pixel_unchecked(fragment, display_origin_x+display_R-(ctxt->r*display_R)+ (ctxt->p*display_R), display_origin_y, makergb(0xFF, 0xFF, 0x00, 1)); #endif @@ -144,7 +145,7 @@ static void spiro_render_fragment(void *context, unsigned ticks, unsigned cpu, f } -rototiller_module_t spiro_module = { +til_module_t spiro_module = { .create_context = spiro_create_context, .destroy_context = spiro_destroy_context, .render_fragment = spiro_render_fragment, diff --git a/src/modules/stars/stars.c b/src/modules/stars/stars.c index a50a099..56e7188 100644 --- a/src/modules/stars/stars.c +++ b/src/modules/stars/stars.c @@ -7,10 +7,11 @@ #include #include +#include "til.h" +#include "til_fb.h" +#include "til_settings.h" + #include "draw.h" -#include "fb.h" -#include "rototiller.h" -#include "settings.h" /* Copyright (C) 2017-20 Philip J. Freeman */ @@ -94,7 +95,7 @@ static void stars_destroy_context(void *context) } -static void stars_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void stars_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { stars_context_t *ctxt = context; struct points* iterator; @@ -113,7 +114,7 @@ static void stars_render_fragment(void *context, unsigned ticks, unsigned cpu, f max_radius=1.f+((width+height)*.001f); - fb_fragment_zero(fragment); + til_fb_fragment_zero(fragment); iterator=ctxt->points; for(;;) @@ -147,7 +148,7 @@ static void stars_render_fragment(void *context, unsigned ticks, unsigned cpu, f opacity = 1; if (pos_x>0 && pos_x0 && pos_yoffset_y = tmp_y; } -int stars_setup(const settings_t *settings, setting_desc_t **next_setting) +int stars_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) { const char *rot_adj; const char *rot_adj_values[] = { @@ -213,15 +214,15 @@ int stars_setup(const settings_t *settings, setting_desc_t **next_setting) NULL }; - rot_adj = settings_get_value(settings, "rot_adj"); + rot_adj = til_settings_get_value(settings, "rot_adj"); if(!rot_adj) { int ret_val; - ret_val = setting_desc_clone(&(setting_desc_t){ + ret_val = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Rotation Rate", .key = "rot_adj", .regex = "\\.[0-9]+", - .preferred = SETTINGS_STR(DEFAULT_ROT_ADJ), + .preferred = TIL_SETTINGS_STR(DEFAULT_ROT_ADJ), .values = rot_adj_values, .annotations = NULL }, next_setting); @@ -236,7 +237,7 @@ int stars_setup(const settings_t *settings, setting_desc_t **next_setting) return 0; } -rototiller_module_t stars_module = { +til_module_t stars_module = { .create_context = stars_create_context, .destroy_context = stars_destroy_context, .render_fragment = stars_render_fragment, diff --git a/src/modules/submit/submit.c b/src/modules/submit/submit.c index 7b4fd91..288a69a 100644 --- a/src/modules/submit/submit.c +++ b/src/modules/submit/submit.c @@ -20,10 +20,10 @@ #include #include -#include "fb.h" -#include "rototiller.h" -#include "settings.h" -#include "util.h" +#include "til.h" +#include "til_fb.h" +#include "til_settings.h" +#include "til_util.h" #include "grid/grid.h" @@ -185,7 +185,7 @@ static inline uint32_t sample_grid(submit_context_t *ctxt, float x, float y) } -static void draw_grid(submit_context_t *ctxt, fb_fragment_t *fragment) +static void draw_grid(submit_context_t *ctxt, til_fb_fragment_t *fragment) { float xscale = ((float)GRID_SIZE - 1.f) / (float)fragment->frame_width; float yscale = ((float)GRID_SIZE - 1.f) / (float)fragment->frame_height; @@ -196,13 +196,13 @@ static void draw_grid(submit_context_t *ctxt, fb_fragment_t *fragment) /* TODO: this could be optimized a bit! i.e. don't recompute the y for every x etc. */ color = sample_grid(ctxt, .5f + ((float)(fragment->x + x)) * xscale, .5f + ((float)(fragment->y + y)) * yscale); - fb_fragment_put_pixel_unchecked(fragment, fragment->x + x, fragment->y + y, color); + til_fb_fragment_put_pixel_unchecked(fragment, fragment->x + x, fragment->y + y, color); } } } -static void draw_grid_bilerp(submit_context_t *ctxt, fb_fragment_t *fragment) +static void draw_grid_bilerp(submit_context_t *ctxt, til_fb_fragment_t *fragment) { float xscale = ((float)GRID_SIZE - 1.f) / (float)fragment->frame_width; float yscale = ((float)GRID_SIZE - 1.f) / (float)fragment->frame_height; @@ -213,7 +213,7 @@ static void draw_grid_bilerp(submit_context_t *ctxt, fb_fragment_t *fragment) /* TODO: this could be optimized a bit! i.e. don't recompute the y for every x etc. */ color = sample_grid_bilerp(ctxt, .5f + ((float)(fragment->x + x)) * xscale, .5f + ((float)(fragment->y + y)) * yscale); - fb_fragment_put_pixel_unchecked(fragment, fragment->x + x, fragment->y + y, color); + til_fb_fragment_put_pixel_unchecked(fragment, fragment->x + x, fragment->y + y, color); } } } @@ -284,13 +284,13 @@ static void submit_destroy_context(void *context) } -static int submit_fragmenter(void *context, const fb_fragment_t *fragment, unsigned number, fb_fragment_t *res_fragment) +static int submit_fragmenter(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment) { - return fb_fragment_tile_single(fragment, 32, number, res_fragment); + return til_fb_fragment_tile_single(fragment, 32, number, res_fragment); } -static void submit_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void submit_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { submit_context_t *ctxt = context; @@ -311,7 +311,7 @@ static void submit_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, } -static void submit_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void submit_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { submit_context_t *ctxt = context; @@ -322,11 +322,11 @@ static void submit_render_fragment(void *context, unsigned ticks, unsigned cpu, } -static int submit_setup(const settings_t *settings, setting_desc_t **next_setting) +static int submit_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) { const char *bilerp; - bilerp = settings_get_value(settings, "bilerp"); + bilerp = til_settings_get_value(settings, "bilerp"); if (!bilerp) { const char *values[] = { "off", @@ -335,7 +335,7 @@ static int submit_setup(const settings_t *settings, setting_desc_t **next_settin }; int r; - r = setting_desc_clone(&(setting_desc_t){ + r = til_setting_desc_clone(&(til_setting_desc_t){ .name = "Bilinear Interpolation of Cell Colors", .key = "bilerp", .regex = NULL, @@ -358,7 +358,7 @@ static int submit_setup(const settings_t *settings, setting_desc_t **next_settin } -rototiller_module_t submit_module = { +til_module_t submit_module = { .create_context = submit_create_context, .destroy_context = submit_destroy_context, .prepare_frame = submit_prepare_frame, diff --git a/src/modules/swab/swab.c b/src/modules/swab/swab.c index a8db372..44b9f21 100644 --- a/src/modules/swab/swab.c +++ b/src/modules/swab/swab.c @@ -21,11 +21,11 @@ #include #include -#include "din/din.h" +#include "til.h" +#include "til_fb.h" +#include "til_util.h" -#include "fb.h" -#include "rototiller.h" -#include "util.h" +#include "din/din.h" typedef struct swab_context_t { @@ -92,15 +92,15 @@ static void swab_destroy_context(void *context) } -static int swab_fragmenter(void *context, const fb_fragment_t *fragment, unsigned number, fb_fragment_t *res_fragment) +static int swab_fragmenter(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment) { swab_context_t *ctxt = context; - return fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); + return til_fb_fragment_slice_single(fragment, ctxt->n_cpus, number, res_fragment); } -static void swab_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter) +static void swab_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { swab_context_t *ctxt = context; @@ -111,7 +111,7 @@ static void swab_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, f } -static void swab_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void swab_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { swab_context_t *ctxt = context; float cos_r = cos(ctxt->r); @@ -134,13 +134,13 @@ static void swab_render_fragment(void *context, unsigned ticks, unsigned cpu, fb color.b = din(ctxt->din, &(v3f_t){ .x = (float)x * xscale * .81f, .y = (float)y * yscale * .81f, .z = z2 }) * t; pixel = color_to_uint32(color); - fb_fragment_put_pixel_unchecked(fragment, x, y, pixel); + til_fb_fragment_put_pixel_unchecked(fragment, x, y, pixel); } } } -rototiller_module_t swab_module = { +til_module_t swab_module = { .create_context = swab_create_context, .destroy_context = swab_destroy_context, .prepare_frame = swab_prepare_frame, diff --git a/src/modules/swarm/swarm.c b/src/modules/swarm/swarm.c index 4ebd79e..0b320fb 100644 --- a/src/modules/swarm/swarm.c +++ b/src/modules/swarm/swarm.c @@ -24,8 +24,8 @@ #include #include -#include "fb.h" -#include "rototiller.h" +#include "til.h" +#include "til_fb.h" #define SWARM_SIZE (32 * 1024) #define SWARM_ZCONST 4.f @@ -236,13 +236,13 @@ static void swarm_update(swarm_context_t *ctxt, unsigned ticks) } -static void swarm_render_fragment(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment) +static void swarm_render_fragment(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { swarm_context_t *ctxt = context; swarm_update(ctxt, ticks); - fb_fragment_zero(fragment); + til_fb_fragment_zero(fragment); { float fw = fragment->frame_width, fh = fragment->frame_height; @@ -261,13 +261,13 @@ static void swarm_render_fragment(void *context, unsigned ticks, unsigned cpu, f nc.x = nc.x * fw + fw; nc.y = nc.y * fh + fh; - fb_fragment_put_pixel_checked(fragment, nc.x, nc.y, color); + til_fb_fragment_put_pixel_checked(fragment, nc.x, nc.y, color); } } } -rototiller_module_t swarm_module = { +til_module_t swarm_module = { .create_context = swarm_create_context, .destroy_context = swarm_destroy_context, .render_fragment = swarm_render_fragment, diff --git a/src/rototiller.c b/src/rototiller.c deleted file mode 100644 index 2a3d45c..0000000 --- a/src/rototiller.c +++ /dev/null @@ -1,207 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "settings.h" -#include "fb.h" -#include "rototiller.h" -#include "threads.h" -#include "util.h" - -/* Copyright (C) 2016 Vito Caputo */ - -#define DEFAULT_MODULE "rtv" - -static threads_t *rototiller_threads; - -extern rototiller_module_t compose_module; -extern rototiller_module_t drizzle_module; -extern rototiller_module_t flui2d_module; -extern rototiller_module_t julia_module; -extern rototiller_module_t meta2d_module; -extern rototiller_module_t montage_module; -extern rototiller_module_t pixbounce_module; -extern rototiller_module_t plasma_module; -extern rototiller_module_t plato_module; -extern rototiller_module_t ray_module; -extern rototiller_module_t roto_module; -extern rototiller_module_t rtv_module; -extern rototiller_module_t snow_module; -extern rototiller_module_t sparkler_module; -extern rototiller_module_t spiro_module; -extern rototiller_module_t stars_module; -extern rototiller_module_t submit_module; -extern rototiller_module_t swab_module; -extern rototiller_module_t swarm_module; - -static const rototiller_module_t *modules[] = { - &compose_module, - &drizzle_module, - &flui2d_module, - &julia_module, - &meta2d_module, - &montage_module, - &pixbounce_module, - &plasma_module, - &plato_module, - &ray_module, - &roto_module, - &rtv_module, - &snow_module, - &sparkler_module, - &spiro_module, - &stars_module, - &submit_module, - &swab_module, - &swarm_module, -}; - - -/* initialize rototiller (create rendering threads) */ -int rototiller_init(void) -{ - if (!(rototiller_threads = threads_create())) - return -errno; - - return 0; -} - - -/* wait for all threads to be idle */ -void rototiller_quiesce(void) -{ - threads_wait_idle(rototiller_threads); -} - - -void rototiller_shutdown(void) -{ - threads_destroy(rototiller_threads); -} - - -const rototiller_module_t * rototiller_lookup_module(const char *name) -{ - assert(name); - - for (size_t i = 0; i < nelems(modules); i++) { - if (!strcasecmp(name, modules[i]->name)) - return modules[i]; - } - - return NULL; -} - - -void rototiller_get_modules(const rototiller_module_t ***res_modules, size_t *res_n_modules) -{ - assert(res_modules); - assert(res_n_modules); - - *res_modules = modules; - *res_n_modules = nelems(modules); -} - - -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; - - module->prepare_frame(context, ticks, threads_num_threads(threads), fragment, &fragmenter); - - if (module->render_fragment) { - threads_frame_submit(threads, fragment, fragmenter, module->render_fragment, context, ticks); - threads_wait_idle(threads); - } - - } else if (module->render_fragment) - module->render_fragment(context, ticks, 0, fragment); - - if (module->finish_frame) - module->finish_frame(context, ticks, fragment); -} - - -/* This is a public interface to the threaded module rendering intended for use by - * modules that wish to get the output of other modules for their own use. - */ -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); -} - -int rototiller_module_create_context(const rototiller_module_t *module, unsigned ticks, void **res_context) -{ - void *context; - - assert(module); - assert(res_context); - - if (!module->create_context) - return 0; - - context = module->create_context(ticks, threads_num_threads(rototiller_threads)); - if (!context) - return -ENOMEM; - - *res_context = context; - - return 0; -} - - -/* select module if not yet selected, then setup the module. */ -int rototiller_module_setup(settings_t *settings, setting_desc_t **next_setting) -{ - const rototiller_module_t *module; - const char *name; - - name = settings_get_key(settings, 0); - if (!name) { - const char *values[nelems(modules) + 1] = {}; - const char *annotations[nelems(modules) + 1] = {}; - setting_desc_t *desc; - unsigned i; - int r; - - for (i = 0; i < nelems(modules); i++) { - values[i] = modules[i]->name; - annotations[i] = modules[i]->description; - } - - r = setting_desc_clone(&(setting_desc_t){ - .name = "Renderer Module", - .key = NULL, - .regex = "[a-zA-Z0-9]+", - .preferred = DEFAULT_MODULE, - .values = values, - .annotations = annotations - }, next_setting); - if (r < 0) - return r; - - return 1; - } - - module = rototiller_lookup_module(name); - if (!module) - return -EINVAL; - - if (module->setup) - return module->setup(settings, next_setting); - - return 0; -} diff --git a/src/rototiller.h b/src/rototiller.h deleted file mode 100644 index 56e1a90..0000000 --- a/src/rototiller.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _ROTOTILLER_H -#define _ROTOTILLER_H - -#include "fb.h" - -/* rototiller_fragmenter produces fragments from an input fragment, num being the desired fragment for the current call. - * return value of 1 means a fragment has been produced, 0 means num is beyond the end of fragments. */ -typedef int (*rototiller_fragmenter_t)(void *context, const fb_fragment_t *fragment, unsigned number, fb_fragment_t *res_fragment); - -typedef struct settings_t settings; -typedef struct setting_desc_t setting_desc_t; -typedef struct knob_t knob_t; - -typedef struct rototiller_module_t { - void * (*create_context)(unsigned ticks, unsigned n_cpus); - void (*destroy_context)(void *context); - void (*prepare_frame)(void *context, unsigned ticks, unsigned n_cpus, fb_fragment_t *fragment, rototiller_fragmenter_t *res_fragmenter); - void (*render_fragment)(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment); - void (*finish_frame)(void *context, unsigned ticks, fb_fragment_t *fragment); - int (*setup)(const settings_t *settings, setting_desc_t **next_setting); - size_t (*knobs)(void *context, knob_t **res_knobs); - char *name; - char *description; - char *author; - char *license; -} rototiller_module_t; - -int rototiller_init(void); -void rototiller_quiesce(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 diff --git a/src/sdl_fb.c b/src/sdl_fb.c index bff7b90..4a2b562 100644 --- a/src/sdl_fb.c +++ b/src/sdl_fb.c @@ -4,8 +4,8 @@ #include #include -#include "fb.h" -#include "settings.h" +#include "til_fb.h" +#include "til_settings.h" /* sdl fb backend, everything sdl-specific in rototiller resides here. */ @@ -26,60 +26,60 @@ struct sdl_fb_page_t { }; -static int sdl_fb_setup(const settings_t *settings, setting_desc_t **next_setting) +static int sdl_fb_setup(const til_settings_t *settings, til_setting_desc_t **next_setting) { - const char *fullscreen_values[] = { - "off", - "on", - NULL - }; - const setting_desc_t descs[] = { - { - .name = "SDL Fullscreen Mode", - .key = "fullscreen", - .regex = NULL, - .preferred = fullscreen_values[0], - .values = fullscreen_values, - .annotations = NULL - }, { - .name = "SDL Window size", - .key = "size", - .regex = "[1-9][0-9]*[xX][1-9][0-9]*", - .preferred = "640x480", - .values = NULL, - .annotations = NULL - }, - }; - const char *fullscreen; - int r; - - - fullscreen = settings_get_value(settings, "fullscreen"); + const char *fullscreen_values[] = { + "off", + "on", + NULL + }; + const til_setting_desc_t descs[] = { + { + .name = "SDL Fullscreen Mode", + .key = "fullscreen", + .regex = NULL, + .preferred = fullscreen_values[0], + .values = fullscreen_values, + .annotations = NULL + }, { + .name = "SDL Window size", + .key = "size", + .regex = "[1-9][0-9]*[xX][1-9][0-9]*", + .preferred = "640x480", + .values = NULL, + .annotations = NULL + }, + }; + const char *fullscreen; + int r; + + + fullscreen = til_settings_get_value(settings, "fullscreen"); if (!fullscreen) { - r = setting_desc_clone(&descs[0], next_setting); + r = til_setting_desc_clone(&descs[0], next_setting); if (r < 0) return r; return 1; } - r = setting_desc_check(&descs[0], fullscreen); + r = til_setting_desc_check(&descs[0], fullscreen); if (r < 0) return r; if (!strcasecmp(fullscreen, "off")) { const char *size; - size = settings_get_value(settings, "size"); + size = til_settings_get_value(settings, "size"); if (!size) { - r = setting_desc_clone(&descs[1], next_setting); + r = til_setting_desc_clone(&descs[1], next_setting); if (r < 0) return r; return 1; } - r = setting_desc_check(&descs[1], size); + r = til_setting_desc_check(&descs[1], size); if (r < 0) return r; } @@ -103,7 +103,7 @@ static int sdl_err_to_errno(int err) } } -static int sdl_fb_init(const settings_t *settings, void **res_context) +static int sdl_fb_init(const til_settings_t *settings, void **res_context) { const char *fullscreen; const char *size; @@ -113,11 +113,11 @@ static int sdl_fb_init(const settings_t *settings, void **res_context) assert(settings); assert(res_context); - fullscreen = settings_get_value(settings, "fullscreen"); + fullscreen = til_settings_get_value(settings, "fullscreen"); if (!fullscreen) return -EINVAL; - size = settings_get_value(settings, "size"); + size = til_settings_get_value(settings, "size"); if (!size && !strcasecmp(fullscreen, "off")) return -EINVAL; @@ -162,7 +162,7 @@ static int sdl_fb_init(const settings_t *settings, void **res_context) } -static void sdl_fb_shutdown(fb_t *fb, void *context) +static void sdl_fb_shutdown(til_fb_t *fb, void *context) { sdl_fb_t *c = context; @@ -171,7 +171,7 @@ static void sdl_fb_shutdown(fb_t *fb, void *context) } -static int sdl_fb_acquire(fb_t *fb, void *context, void *page) +static int sdl_fb_acquire(til_fb_t *fb, void *context, void *page) { sdl_fb_t *c = context; sdl_fb_page_t *p = page; @@ -192,7 +192,7 @@ static int sdl_fb_acquire(fb_t *fb, void *context, void *page) } -static void sdl_fb_release(fb_t *fb, void *context) +static void sdl_fb_release(til_fb_t *fb, void *context) { sdl_fb_t *c = context; @@ -202,7 +202,7 @@ static void sdl_fb_release(fb_t *fb, void *context) } -static void * sdl_fb_page_alloc(fb_t *fb, void *context, fb_page_t *res_page) +static void * sdl_fb_page_alloc(til_fb_t *fb, void *context, til_fb_page_t *res_page) { sdl_fb_t *c = context; sdl_fb_page_t *p; @@ -225,7 +225,7 @@ static void * sdl_fb_page_alloc(fb_t *fb, void *context, fb_page_t *res_page) } -static int sdl_fb_page_free(fb_t *fb, void *context, void *page) +static int sdl_fb_page_free(til_fb_t *fb, void *context, void *page) { sdl_fb_t *c = context; sdl_fb_page_t *p = page; @@ -253,7 +253,7 @@ static int sdl_ready() } -static int sdl_fb_page_flip(fb_t *fb, void *context, void *page) +static int sdl_fb_page_flip(til_fb_t *fb, void *context, void *page) { sdl_fb_t *c = context; sdl_fb_page_t *p = page; @@ -278,7 +278,7 @@ static int sdl_fb_page_flip(fb_t *fb, void *context, void *page) } -fb_ops_t sdl_fb_ops = { +til_fb_ops_t sdl_fb_ops = { .setup = sdl_fb_setup, .init = sdl_fb_init, .shutdown = sdl_fb_shutdown, diff --git a/src/settings.c b/src/settings.c deleted file mode 100644 index e54a690..0000000 --- a/src/settings.c +++ /dev/null @@ -1,391 +0,0 @@ -#include -#include -#include -#include -#include - -#include "settings.h" -#include "util.h" - -#ifdef __WIN32__ -char * strndup(const char *s, size_t n) -{ - size_t len; - char *buf; - - for (len = 0; len < n; len++) { - if (!s[len]) - break; - } - - buf = calloc(len + 1, sizeof(char)); - if (!buf) - return NULL; - - memcpy(buf, s, len); - - return buf; -} -#endif - -/* Split form of key=value[,key=value...] settings string */ -typedef struct settings_t { - unsigned num; - const char **keys; - const char **values; -} settings_t; - -typedef enum settings_fsm_state_t { - SETTINGS_FSM_STATE_KEY, - SETTINGS_FSM_STATE_EQUAL, - SETTINGS_FSM_STATE_VALUE, - SETTINGS_FSM_STATE_COMMA, -} settings_fsm_state_t; - - -static int add_value(settings_t *settings, const char *key, const char *value) -{ - assert(settings); - - settings->num++; - /* TODO errors */ - settings->keys = realloc(settings->keys, settings->num * sizeof(const char **)); - settings->values = realloc(settings->values, settings->num * sizeof(const char **)); - settings->keys[settings->num - 1] = key; - settings->values[settings->num - 1] = value; - - return 0; -} - - -/* split settings_string into a data structure */ -settings_t * settings_new(const char *settings_string) -{ - settings_fsm_state_t state = SETTINGS_FSM_STATE_KEY; - const char *p, *token; - settings_t *settings; - - settings = calloc(1, sizeof(settings_t)); - if (!settings) - return NULL; - - if (!settings_string) - return settings; - - /* TODO: unescaping? */ - for (token = p = settings_string; ;p++) { - - switch (state) { - case SETTINGS_FSM_STATE_COMMA: - token = p; - state = SETTINGS_FSM_STATE_KEY; - break; - - case SETTINGS_FSM_STATE_KEY: - if (*p == '=' || *p == ',' || *p == '\0') { - add_value(settings, strndup(token, p - token), NULL); - - if (*p == '=') - state = SETTINGS_FSM_STATE_EQUAL; - else if (*p == ',') - state = SETTINGS_FSM_STATE_COMMA; - } - break; - - case SETTINGS_FSM_STATE_EQUAL: - token = p; - state = SETTINGS_FSM_STATE_VALUE; - break; - - case SETTINGS_FSM_STATE_VALUE: - if (*p == ',' || *p == '\0') { - settings->values[settings->num - 1] = strndup(token, p - token); - state = SETTINGS_FSM_STATE_COMMA; - } - break; - - default: - assert(0); - } - - if (*p == '\0') - break; - } - - /* FIXME: this should probably never leave a value or key entry NULL */ - - return settings; -} - - -/* free structure attained via settings_new() */ -settings_t * settings_free(settings_t *settings) -{ - - if (settings) { - for (unsigned i = 0; i < settings->num; i++) { - free((void *)settings->keys[i]); - free((void *)settings->values[i]); - } - - free((void *)settings->keys); - free((void *)settings->values); - free(settings); - } - - return NULL; -} - - -/* find key= in settings, return dup of value side or NULL if missing */ -const char * settings_get_value(const settings_t *settings, const char *key) -{ - int i; - - assert(settings); - assert(key); - - for (i = 0; i < settings->num; i++) { - if (!strcmp(key, settings->keys[i])) - return settings->values[i]; - } - - return NULL; -} - - -/* return positional key from settings */ -const char * settings_get_key(const settings_t *settings, unsigned pos) -{ - assert(settings); - - if (pos < settings->num) - return settings->keys[pos]; - - return NULL; -} - - -/* add key=value to the settings, - * or just key if value is NULL. - */ -/* returns < 0 on error */ -int settings_add_value(settings_t *settings, const char *key, const char *value) -{ - assert(settings); - assert(key); - - return add_value(settings, strdup(key), value ? strdup(value) : NULL); -} - - -/* apply the supplied setting description generators to the supplied settings */ -/* returns 0 when input settings are complete */ -/* returns 1 when input settings are incomplete, storing the next setting's description needed in *next_setting */ -/* returns -errno on error */ -int settings_apply_desc_generators(const settings_t *settings, const setting_desc_generator_t generators[], unsigned n_generators, void *setup_context, setting_desc_t **next_setting) -{ - unsigned i; - setting_desc_t *next; - - assert(settings); - assert(generators); - assert(n_generators > 0); - assert(next_setting); - - for (i = 0; i < n_generators; i++) { - const setting_desc_generator_t *g = &generators[i]; - const char *value; - setting_desc_t *desc; - int r; - - r = g->func(setup_context, &desc); - if (r < 0) - return r; - - assert(desc); - - value = settings_get_value(settings, g->key); - if (value) { - int r; - - r = setting_desc_check(desc, value); - setting_desc_free(desc); - if (r < 0) - return r; - - if (g->value_ptr) - *g->value_ptr = value; - - continue; - } - - *next_setting = desc; - - return 1; - } - - return 0; -} - - -/* convenience helper for creating a new setting description */ -/* copies of everything supplied are made in newly allocated memory, stored @ res_desc */ -/* returns < 0 on error */ -int setting_desc_clone(const setting_desc_t *desc, setting_desc_t **res_desc) -{ - setting_desc_t *d; - - assert(desc); - assert(desc->name); - assert(desc->preferred); /* XXX: require a preferred default? */ - assert(!desc->annotations || desc->values); - assert(res_desc); - - d = calloc(1, sizeof(setting_desc_t)); - if (!d) - return -ENOMEM; - - d->name = strdup(desc->name); - if (desc->key) /* This is inappropriately subtle, but when key is NULL, the value will be the key, and there will be no value side at all. */ - d->key = strdup(desc->key); - if (desc->regex) - d->regex = strdup(desc->regex); - - d->preferred = strdup(desc->preferred); - - if (desc->values) { - unsigned i; - - for (i = 0; desc->values[i]; i++); - - d->values = calloc(i + 1, sizeof(*desc->values)); - - if (desc->annotations) - d->annotations = calloc(i + 1, sizeof(*desc->annotations)); - - for (i = 0; desc->values[i]; i++) { - d->values[i] = strdup(desc->values[i]); - - if (desc->annotations) { - assert(desc->annotations[i]); - d->annotations[i] = strdup(desc->annotations[i]); - } - } - } - - d->random = desc->random; - - /* TODO: handle allocation errors above... */ - *res_desc = d; - - return 0; -} - - -setting_desc_t * setting_desc_free(setting_desc_t *desc) -{ - if (desc) { - free((void *)desc->name); - free((void *)desc->key); - free((void *)desc->regex); - free((void *)desc->preferred); - - if (desc->values) { - for (unsigned i = 0; desc->values[i]; i++) { - free((void *)desc->values[i]); - - if (desc->annotations) - free((void *)desc->annotations[i]); - } - - free((void *)desc->values); - free((void *)desc->annotations); - } - - free(desc); - } - - return NULL; -} - - -int setting_desc_check(const setting_desc_t *desc, const char *value) -{ - assert(desc); - - if (desc->values) { - - for (int i = 0; desc->values[i]; i++) { - if (!strcasecmp(desc->values[i], value)) - return 0; - } - - return -EINVAL; - } - - /* TODO: apply regex check */ - - return 0; -} - - -/* wrapper around sprintf for convenient buffer size computation */ -/* supply NULL buf when computing size, size and offset are ignored. - * supply non-NULL for actual writing into buf of size bytes @ offset. - * return value is number of bytes (potentially if !buf) written - */ -static int snpf(char *buf, size_t size, off_t offset, const char *format, ...) -{ - size_t avail = 0; - va_list ap; - int r; - - if (buf) { - assert(size > offset); - - avail = size - offset; - buf += offset; - } - - va_start(ap, format); - r = vsnprintf(buf, avail, format, ap); - va_end(ap); - - return r; -} - - -char * settings_as_arg(const settings_t *settings) -{ - char *buf = NULL; - size_t off, size; - - /* intentionally avoided open_memstream for portability reasons */ - for (;;) { - unsigned i; - - for (i = off = 0; i < settings->num; i++) { - if (i > 0) - off += snpf(buf, size, off, ","); - - off += snpf(buf, size, off, "%s", settings->keys[i]); - - if (settings->values[i]) - off += snpf(buf, size, off, "=%s", settings->values[i]); - } - - if (!buf) { - size = off + 1; - buf = calloc(size, sizeof(char)); - if (!buf) - return NULL; - - continue; - } - - break; - } - - return buf; -} diff --git a/src/settings.h b/src/settings.h deleted file mode 100644 index 9916ebb..0000000 --- a/src/settings.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _SETTINGS_H -#define _SETTINGS_H - -#include - -/* Individual setting description */ -typedef struct setting_desc_t { - const char *name; /* long-form/human name for setting */ - const char *key; /* short-form/key for setting, used as left side of =value in settings string */ - const char *regex; /* value must conform to this regex */ - const char *preferred; /* if there's a default, this is it */ - const char **values; /* if a set of values is provided, listed here */ - const char **annotations; /* if a set of values is provided, annotations for those values may be listed here */ - char * (*random)(void);/* if set, returns a valid random value for this setting */ -} setting_desc_t; - -/* For conveniently representing setting description generators */ -typedef struct setting_desc_generator_t { - const char *key; /* key this generator applies to */ - const char **value_ptr; /* where to put the value */ - int (*func)(void *setup_context, setting_desc_t **res_desc); -} setting_desc_generator_t; - -typedef struct settings_t settings_t; - -settings_t * settings_new(const char *settings); -settings_t * settings_free(settings_t *settings); -const char * settings_get_value(const settings_t *settings, const char *key); -const char * settings_get_key(const settings_t *settings, unsigned pos); -int settings_add_value(settings_t *settings, const char *key, const char *value); -char * settings_as_arg(const settings_t *settings); -int settings_apply_desc_generators(const settings_t *settings, const setting_desc_generator_t generators[], unsigned n_generators, void *setup_context, setting_desc_t **next_setting); - -int setting_desc_clone(const setting_desc_t *desc, setting_desc_t **res_desc); -setting_desc_t * setting_desc_free(setting_desc_t *desc); -int setting_desc_check(const setting_desc_t *desc, const char *value); - -#ifndef SETTINGS_STR -#define _SETTINGS_STR(s) #s -#define SETTINGS_STR(s) _SETTINGS_STR(s) -#endif - -#endif diff --git a/src/setup.c b/src/setup.c index 2f0353d..9f67374 100644 --- a/src/setup.c +++ b/src/setup.c @@ -1,11 +1,11 @@ #include #include -#include "settings.h" -#include "util.h" +#include "til_settings.h" +#include "til_util.h" /* add key=value, but if key is NULL, use value as key. */ -static int add_value(settings_t *settings, const char *key, const char *value) +static int add_value(til_settings_t *settings, const char *key, const char *value) { assert(settings); @@ -16,17 +16,17 @@ static int add_value(settings_t *settings, const char *key, const char *value) assert(key); - return settings_add_value(settings, key, value); + return til_settings_add_value(settings, key, value); } /* returns negative on error, otherwise number of additions made to settings */ -int setup_interactively(settings_t *settings, int (*setup_func)(settings_t *settings, setting_desc_t **next), int defaults) +int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings_t *settings, til_setting_desc_t **next), int defaults) { - unsigned additions = 0; - char buf[256] = "\n"; - setting_desc_t *next; - int r; + unsigned additions = 0; + char buf[256] = "\n"; + til_setting_desc_t *next; + int r; assert(settings); assert(setup_func); @@ -117,7 +117,7 @@ int setup_interactively(settings_t *settings, int (*setup_func)(settings_t *sett } _next: - setting_desc_free(next); + til_setting_desc_free(next); } return r < 0 ? r : additions; diff --git a/src/setup.h b/src/setup.h index 2f190f4..878e68b 100644 --- a/src/setup.h +++ b/src/setup.h @@ -1,8 +1,8 @@ #ifndef _SETUP_H #define _SETUP_H -#include "settings.h" +#include "til_settings.h" -int setup_interactively(settings_t *settings, int (*setup_func)(settings_t *settings, setting_desc_t **next), int defaults); +int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings_t *settings, til_setting_desc_t **next), int defaults); #endif diff --git a/src/threads.c b/src/threads.c deleted file mode 100644 index dd1d620..0000000 --- a/src/threads.c +++ /dev/null @@ -1,168 +0,0 @@ -#include -#include -#include - -#include "fb.h" -#include "rototiller.h" -#include "threads.h" -#include "util.h" - -typedef struct thread_t { - threads_t *threads; - pthread_t pthread; - unsigned id; -} thread_t; - -typedef struct threads_t { - unsigned n_threads; - - pthread_mutex_t idle_mutex; - pthread_cond_t idle_cond; - unsigned n_idle; - - pthread_mutex_t frame_mutex; - pthread_cond_t frame_cond; - void (*render_fragment_func)(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment); - void *context; - fb_fragment_t *fragment; - rototiller_fragmenter_t fragmenter; - unsigned ticks; - - unsigned next_fragment; - unsigned frame_num; - - thread_t threads[]; -} threads_t; - - -/* render fragments using the supplied render function */ -static void * thread_func(void *_thread) -{ - thread_t *thread = _thread; - threads_t *threads = thread->threads; - unsigned prev_frame_num = 0; - - pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); - - for (;;) { - - /* wait for a new frame */ - pthread_mutex_lock(&threads->frame_mutex); - pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, &threads->frame_mutex); - while (threads->frame_num == prev_frame_num) - pthread_cond_wait(&threads->frame_cond, &threads->frame_mutex); - prev_frame_num = threads->frame_num; - pthread_cleanup_pop(1); - - /* render fragments */ - for (;;) { - unsigned frag_num; - fb_fragment_t fragment; - - frag_num = __sync_fetch_and_add(&threads->next_fragment, 1); - - if (!threads->fragmenter(threads->context, threads->fragment, frag_num, &fragment)) - break; - - threads->render_fragment_func(threads->context, threads->ticks, thread->id, &fragment); - } - - /* report as idle */ - pthread_mutex_lock(&threads->idle_mutex); - pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, &threads->idle_mutex); - threads->n_idle++; - if (threads->n_idle == threads->n_threads) /* Frame finished! Notify potential waiter. */ - pthread_cond_signal(&threads->idle_cond); - pthread_cleanup_pop(1); - } - - return NULL; -} - - -/* wait for all threads to be idle */ -void threads_wait_idle(threads_t *threads) -{ - pthread_mutex_lock(&threads->idle_mutex); - pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, &threads->idle_mutex); - while (threads->n_idle < threads->n_threads) - pthread_cond_wait(&threads->idle_cond, &threads->idle_mutex); - pthread_cleanup_pop(1); -} - - -/* submit a frame's fragments to the threads */ -void threads_frame_submit(threads_t *threads, fb_fragment_t *fragment, rototiller_fragmenter_t fragmenter, void (*render_fragment_func)(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment), void *context, unsigned ticks) -{ - threads_wait_idle(threads); /* XXX: likely non-blocking; already happens pre page flip */ - - pthread_mutex_lock(&threads->frame_mutex); - pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, &threads->frame_mutex); - threads->fragment = fragment; - threads->fragmenter = fragmenter; - threads->render_fragment_func = render_fragment_func; - threads->context = context; - threads->ticks = ticks; - threads->frame_num++; - threads->n_idle = threads->next_fragment = 0; - pthread_cond_broadcast(&threads->frame_cond); - pthread_cleanup_pop(1); -} - - -/* create threads instance, a thread per cpu is created */ -threads_t * threads_create(void) -{ - unsigned i, num = get_ncpus(); - threads_t *threads; - - threads = calloc(1, sizeof(threads_t) + sizeof(thread_t) * num); - if (!threads) - return NULL; - - threads->n_idle = threads->n_threads = num; - - pthread_mutex_init(&threads->idle_mutex, NULL); - pthread_cond_init(&threads->idle_cond, NULL); - - pthread_mutex_init(&threads->frame_mutex, NULL); - pthread_cond_init(&threads->frame_cond, NULL); - - for (i = 0; i < num; i++) { - thread_t *thread = &threads->threads[i]; - - thread->threads = threads; - thread->id = i; - pthread_create(&thread->pthread, NULL, thread_func, thread); - } - - return threads; -} - - -/* destroy a threads instance */ -void threads_destroy(threads_t *threads) -{ - unsigned i; - - for (i = 0; i < threads->n_threads; i++) - pthread_cancel(threads->threads[i].pthread); - - for (i = 0; i < threads->n_threads; i++) - pthread_join(threads->threads[i].pthread, NULL); - - pthread_mutex_destroy(&threads->idle_mutex); - pthread_cond_destroy(&threads->idle_cond); - - pthread_mutex_destroy(&threads->frame_mutex); - pthread_cond_destroy(&threads->frame_cond); - - free(threads); -} - - -/* return the number of threads */ -unsigned threads_num_threads(threads_t *threads) -{ - return threads->n_threads; -} diff --git a/src/threads.h b/src/threads.h deleted file mode 100644 index f0ffe6f..0000000 --- a/src/threads.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _THREADS_H -#define _THREADS_H - -typedef struct fb_fragment_t fb_fragment_t; -typedef struct rototiller_frame_t rototiller_frame_t; -typedef struct threads_t threads_t; - -threads_t * threads_create(); -void threads_destroy(threads_t *threads); - -void threads_frame_submit(threads_t *threads, fb_fragment_t *fragment, rototiller_fragmenter_t fragmenter, void (*render_fragment_func)(void *context, unsigned ticks, unsigned cpu, fb_fragment_t *fragment), void *context, unsigned ticks); -void threads_wait_idle(threads_t *threads); -unsigned threads_num_threads(threads_t *threads); - -#endif diff --git a/src/til.c b/src/til.c new file mode 100644 index 0000000..0989a6d --- /dev/null +++ b/src/til.c @@ -0,0 +1,207 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "til.h" +#include "til_fb.h" +#include "til_settings.h" +#include "til_threads.h" +#include "til_util.h" + +/* Copyright (C) 2016 Vito Caputo */ + +#define DEFAULT_MODULE "rtv" + +static til_threads_t *til_threads; + +extern til_module_t compose_module; +extern til_module_t drizzle_module; +extern til_module_t flui2d_module; +extern til_module_t julia_module; +extern til_module_t meta2d_module; +extern til_module_t montage_module; +extern til_module_t pixbounce_module; +extern til_module_t plasma_module; +extern til_module_t plato_module; +extern til_module_t ray_module; +extern til_module_t roto_module; +extern til_module_t rtv_module; +extern til_module_t snow_module; +extern til_module_t sparkler_module; +extern til_module_t spiro_module; +extern til_module_t stars_module; +extern til_module_t submit_module; +extern til_module_t swab_module; +extern til_module_t swarm_module; + +static const til_module_t *modules[] = { + &compose_module, + &drizzle_module, + &flui2d_module, + &julia_module, + &meta2d_module, + &montage_module, + &pixbounce_module, + &plasma_module, + &plato_module, + &ray_module, + &roto_module, + &rtv_module, + &snow_module, + &sparkler_module, + &spiro_module, + &stars_module, + &submit_module, + &swab_module, + &swarm_module, +}; + + +/* initialize rototiller (create rendering threads) */ +int til_init(void) +{ + if (!(til_threads = til_threads_create())) + return -errno; + + return 0; +} + + +/* wait for all threads to be idle */ +void til_quiesce(void) +{ + til_threads_wait_idle(til_threads); +} + + +void til_shutdown(void) +{ + til_threads_destroy(til_threads); +} + + +const til_module_t * til_lookup_module(const char *name) +{ + assert(name); + + for (size_t i = 0; i < nelems(modules); i++) { + if (!strcasecmp(name, modules[i]->name)) + return modules[i]; + } + + return NULL; +} + + +void til_get_modules(const til_module_t ***res_modules, size_t *res_n_modules) +{ + assert(res_modules); + assert(res_n_modules); + + *res_modules = modules; + *res_n_modules = nelems(modules); +} + + +static void module_render_fragment(const til_module_t *module, void *context, til_threads_t *threads, unsigned ticks, til_fb_fragment_t *fragment) +{ + assert(module); + assert(threads); + assert(fragment); + + if (module->prepare_frame) { + til_fragmenter_t fragmenter; + + module->prepare_frame(context, ticks, til_threads_num_threads(threads), fragment, &fragmenter); + + if (module->render_fragment) { + til_threads_frame_submit(threads, fragment, fragmenter, module->render_fragment, context, ticks); + til_threads_wait_idle(threads); + } + + } else if (module->render_fragment) + module->render_fragment(context, ticks, 0, fragment); + + if (module->finish_frame) + module->finish_frame(context, ticks, fragment); +} + + +/* This is a public interface to the threaded module rendering intended for use by + * modules that wish to get the output of other modules for their own use. + */ +void til_module_render(const til_module_t *module, void *context, unsigned ticks, til_fb_fragment_t *fragment) +{ + module_render_fragment(module, context, til_threads, ticks, fragment); +} + + +int til_module_create_context(const til_module_t *module, unsigned ticks, void **res_context) +{ + void *context; + + assert(module); + assert(res_context); + + if (!module->create_context) + return 0; + + context = module->create_context(ticks, til_threads_num_threads(til_threads)); + if (!context) + return -ENOMEM; + + *res_context = context; + + return 0; +} + + +/* select module if not yet selected, then setup the module. */ +int til_module_setup(til_settings_t *settings, til_setting_desc_t **next_setting) +{ + const til_module_t *module; + const char *name; + + name = til_settings_get_key(settings, 0); + if (!name) { + const char *values[nelems(modules) + 1] = {}; + const char *annotations[nelems(modules) + 1] = {}; + til_setting_desc_t *desc; + int r; + + for (unsigned i = 0; i < nelems(modules); i++) { + values[i] = modules[i]->name; + annotations[i] = modules[i]->description; + } + + r = til_setting_desc_clone(&(til_setting_desc_t){ + .name = "Renderer Module", + .key = NULL, + .regex = "[a-zA-Z0-9]+", + .preferred = DEFAULT_MODULE, + .values = values, + .annotations = annotations + }, next_setting); + if (r < 0) + return r; + + return 1; + } + + module = til_lookup_module(name); + if (!module) + return -EINVAL; + + if (module->setup) + return module->setup(settings, next_setting); + + return 0; +} diff --git a/src/til.h b/src/til.h new file mode 100644 index 0000000..6719693 --- /dev/null +++ b/src/til.h @@ -0,0 +1,37 @@ +#ifndef _TIL_H +#define _TIL_H + +#include "til_fb.h" + +/* til_fragmenter produces fragments from an input fragment, num being the desired fragment for the current call. + * return value of 1 means a fragment has been produced, 0 means num is beyond the end of fragments. */ +typedef int (*til_fragmenter_t)(void *context, const til_fb_fragment_t *fragment, unsigned number, til_fb_fragment_t *res_fragment); + +typedef struct til_settings_t settings; +typedef struct til_setting_desc_t til_setting_desc_t; +typedef struct til_knob_t til_knob_t; + +typedef struct til_module_t { + void * (*create_context)(unsigned ticks, unsigned n_cpus); + void (*destroy_context)(void *context); + void (*prepare_frame)(void *context, unsigned ticks, unsigned n_cpus, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter); + void (*render_fragment)(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment); + void (*finish_frame)(void *context, unsigned ticks, til_fb_fragment_t *fragment); + int (*setup)(const til_settings_t *settings, til_setting_desc_t **next_setting); + size_t (*knobs)(void *context, til_knob_t **res_knobs); + char *name; + char *description; + char *author; + char *license; +} til_module_t; + +int til_init(void); +void til_quiesce(void); +void til_shutdown(void); +const til_module_t * til_lookup_module(const char *name); +void til_get_modules(const til_module_t ***res_modules, size_t *res_n_modules); +void til_module_render(const til_module_t *module, void *context, unsigned ticks, til_fb_fragment_t *fragment); +int til_module_create_context(const til_module_t *module, unsigned ticks, void **res_context); +int til_module_setup(til_settings_t *settings, til_setting_desc_t **next_setting); + +#endif diff --git a/src/til_fb.c b/src/til_fb.c new file mode 100644 index 0000000..3b604e4 --- /dev/null +++ b/src/til_fb.c @@ -0,0 +1,442 @@ +#include +#include +#include +#include +#include + +#include "til_fb.h" +#include "til_settings.h" +#include "til_util.h" + +/* Copyright (C) 2016-2017 Vito Caputo */ + + +/* I've used a separate thread for page-flipping duties because the libdrm api + * (and related kernel ioctl) for page flips doesn't appear to support queueing + * multiple flip requests. In this use case we aren't interactive and wish to + * just accumulate rendered pages until we run out of spare pages, allowing the + * renderer to get as far ahead of vsync as possible, and certainly never + * blocked waiting for vsync unless there's no spare page available for drawing + * into. + * + * In lieu of a queueing mechanism on the drm fd, we must submit the next page + * once the currently submitted page is flipped to - it's at that moment we + * won't get EBUSY from the ioctl any longer. Without a dedicated thread + * submitting flip requests and synchronously consuming their flip events, + * we're liable to introduce latency in the page flip submission if implemented + * in a more opportunistic manner whenever the fb api is entered from the + * render loop. + * + * If the kernel simply let us queue multiple flip requests we could maintain + * our submission queue entirely in the drm fd, and get available pages from + * the drm event handler once our pool of pages is depleted. The kernel on + * vsync could check the fd to see if another flip is queued and there would be + * the least latency possible in submitting the flips - the least likely to + * miss a vsync. This would also elide the need for synchronization in + * userspace between the renderer and the flipper thread, since there would no + * longer be a flipper thread. + * + * Let me know if you're aware of a better way with existing mainline drm! + * + * + * XXX: til_fb_new() used to create a thread which did the equivalent of til_fb_flip() + * continuously in a loop. This posed a problem for the sdl_fb backend, due to + * the need for event pumping in the page flip hook. SDL internally uses TLS + * and requires that the same thread which initialized SDL call the event + * functions. To satisfy this requirement, the body of the flipper thread loop + * has been moved to the til_fb_flip() function. Rototiller's main thread is + * expected to call this repeatedly, turning it effectively into the flipper + * thread. This required rototiller to move what was previously the main + * thread's duties - page rendering dispatch, to a separate thread. + */ + + +/* Most of til_fb_page_t is kept private, the public part is + * just an til_fb_fragment_t describing the whole page. + */ +typedef struct _til_fb_page_t _til_fb_page_t; +struct _til_fb_page_t { + void *ops_page; + + _til_fb_page_t *next, *previous; + til_fb_page_t public_page; +}; + +typedef struct til_fb_t { + const til_fb_ops_t *ops; + void *ops_context; + int n_pages; + + pthread_mutex_t rebuild_mutex; + int rebuild_pages; /* counter of pages needing a rebuild */ + + _til_fb_page_t *active_page; /* page currently displayed */ + + pthread_mutex_t ready_mutex; + pthread_cond_t ready_cond; + _til_fb_page_t *ready_pages_head; /* next pages to flip to */ + _til_fb_page_t *ready_pages_tail; + + pthread_mutex_t inactive_mutex; + pthread_cond_t inactive_cond; + _til_fb_page_t *inactive_pages_head; /* finished pages available for (re)use */ + _til_fb_page_t *inactive_pages_tail; + + unsigned put_pages_count; +} til_fb_t; + +#ifndef container_of +#define container_of(_ptr, _type, _member) \ + (_type *)((void *)(_ptr) - offsetof(_type, _member)) +#endif + + +/* Consumes ready pages queued via til_fb_page_put(), submits them to drm to flip + * on vsync. Produces inactive pages from those replaced, making them + * available to til_fb_page_get(). */ +int til_fb_flip(til_fb_t *fb) +{ + _til_fb_page_t *next_active_page; + int r; + + /* wait for a flip req, submit the req page for flip on vsync, wait for it to flip before making the + * active page inactive/available, repeat. + */ + pthread_mutex_lock(&fb->ready_mutex); + while (!fb->ready_pages_head) + pthread_cond_wait(&fb->ready_cond, &fb->ready_mutex); + + next_active_page = fb->ready_pages_head; + fb->ready_pages_head = next_active_page->next; + if (!fb->ready_pages_head) + fb->ready_pages_tail = NULL; + pthread_mutex_unlock(&fb->ready_mutex); + + /* submit the next active page for page flip on vsync, and wait for it. */ + r = fb->ops->page_flip(fb, fb->ops_context, next_active_page->ops_page); + if (r < 0) /* TODO: vet this: what happens to this page? */ + return r; + + /* now that we're displaying a new page, make the previously active one inactive so rendering can reuse it */ + pthread_mutex_lock(&fb->inactive_mutex); + fb->active_page->next = fb->inactive_pages_head; + fb->inactive_pages_head = fb->active_page; + fb->inactive_pages_head->previous = NULL; + if (fb->inactive_pages_head->next) + fb->inactive_pages_head->next->previous = fb->inactive_pages_head; + else + fb->inactive_pages_tail = fb->inactive_pages_head; + + /* before setting the renderer loose, check if there's more page rebuilding needed, + * and if there is do as much as possible here in the inactive set. Note it's important + * that the renderer take pages from the tail, and we always replenish inactive at the + * head, as well as rebuild pages from the head. + */ + pthread_mutex_lock(&fb->rebuild_mutex); + for (_til_fb_page_t *p = fb->inactive_pages_head; p && fb->rebuild_pages > 0; p = p->next) { + fb->ops->page_free(fb, fb->ops_context, p->ops_page); + p->ops_page = fb->ops->page_alloc(fb, fb->ops_context, &p->public_page); + fb->rebuild_pages--; + } + pthread_mutex_unlock(&fb->rebuild_mutex); + + pthread_cond_signal(&fb->inactive_cond); + pthread_mutex_unlock(&fb->inactive_mutex); + + fb->active_page = next_active_page; + + return 0; +} + + +/* acquire the fb, making page the visible page */ +static int til_fb_acquire(til_fb_t *fb, _til_fb_page_t *page) +{ + int ret; + + ret = fb->ops->acquire(fb, fb->ops_context, page->ops_page); + if (ret < 0) + return ret; + + fb->active_page = page; + + return 0; +} + + +/* release the fb, making the visible page inactive */ +static void til_fb_release(til_fb_t *fb) +{ + fb->ops->release(fb, fb->ops_context); + + /* XXX: this is getting silly, either add a doubly linked list header or + * at least use some functions for this local to this file. + */ + fb->active_page->next = fb->inactive_pages_head; + fb->inactive_pages_head = fb->active_page; + fb->inactive_pages_head->previous = NULL; + if (fb->inactive_pages_head->next) + fb->inactive_pages_head->next->previous = fb->inactive_pages_head; + else + fb->inactive_pages_tail = fb->inactive_pages_head; + + fb->active_page = NULL; +} + + +/* creates a framebuffer page */ +static void til_fb_page_new(til_fb_t *fb) +{ + _til_fb_page_t *page; + + page = calloc(1, sizeof(_til_fb_page_t)); + assert(page); + + page->ops_page = fb->ops->page_alloc(fb, fb->ops_context, &page->public_page); + + pthread_mutex_lock(&fb->inactive_mutex); + page->next = fb->inactive_pages_head; + fb->inactive_pages_head = page; + if (fb->inactive_pages_head->next) + fb->inactive_pages_head->next->previous = fb->inactive_pages_head; + else + fb->inactive_pages_tail = fb->inactive_pages_head; + pthread_mutex_unlock(&fb->inactive_mutex); + +} + + +static void _til_fb_page_free(til_fb_t *fb, _til_fb_page_t *page) +{ + fb->ops->page_free(fb, fb->ops_context, page->ops_page); + + free(page); +} + + +/* get the next inactive page from the fb, waiting if necessary. */ +static inline _til_fb_page_t * _til_fb_page_get(til_fb_t *fb) +{ + _til_fb_page_t *page; + + /* As long as n_pages is >= 3 this won't block unless we're submitting + * pages faster than vhz. + */ + pthread_mutex_lock(&fb->inactive_mutex); + while (!(page = fb->inactive_pages_tail)) + pthread_cond_wait(&fb->inactive_cond, &fb->inactive_mutex); + fb->inactive_pages_tail = page->previous; + if (fb->inactive_pages_tail) + fb->inactive_pages_tail->next = NULL; + else + fb->inactive_pages_head = NULL; + pthread_mutex_unlock(&fb->inactive_mutex); + + page->next = page->previous = NULL; + page->public_page.fragment.zeroed = 0; + + return page; +} + + +/* public interface */ +til_fb_page_t * til_fb_page_get(til_fb_t *fb) +{ + return &(_til_fb_page_get(fb)->public_page); +} + + +/* put a page into the fb, queueing for display */ +static inline void _til_fb_page_put(til_fb_t *fb, _til_fb_page_t *page) +{ + pthread_mutex_lock(&fb->ready_mutex); + if (fb->ready_pages_tail) + fb->ready_pages_tail->next = page; + else + fb->ready_pages_head = page; + + fb->ready_pages_tail = page; + pthread_cond_signal(&fb->ready_cond); + pthread_mutex_unlock(&fb->ready_mutex); +} + + +/* public interface */ + +/* put a page into the fb, queueing for display */ +void til_fb_page_put(til_fb_t *fb, til_fb_page_t *page) +{ + fb->put_pages_count++; + + _til_fb_page_put(fb, container_of(page, _til_fb_page_t, public_page)); +} + + +/* get (and reset) the current count of put pages */ +void til_fb_get_put_pages_count(til_fb_t *fb, unsigned *count) +{ + *count = fb->put_pages_count; + fb->put_pages_count = 0; +} + + +/* free the fb and associated resources */ +til_fb_t * til_fb_free(til_fb_t *fb) +{ + if (fb) { + if (fb->active_page) + til_fb_release(fb); + + /* TODO: free all the pages */ + + if (fb->ops->shutdown && fb->ops_context) + fb->ops->shutdown(fb, fb->ops_context); + + pthread_mutex_destroy(&fb->ready_mutex); + pthread_cond_destroy(&fb->ready_cond); + pthread_mutex_destroy(&fb->inactive_mutex); + pthread_cond_destroy(&fb->inactive_cond); + + free(fb); + } + + return NULL; +} + + +/* create a new fb instance */ +int til_fb_new(const til_fb_ops_t *ops, til_settings_t *settings, int n_pages, til_fb_t **res_fb) +{ + _til_fb_page_t *page; + til_fb_t *fb; + int r; + + assert(ops); + assert(ops->page_alloc); + assert(ops->page_free); + assert(ops->page_flip); + assert(n_pages > 1); + assert(res_fb); + + /* XXX: page-flipping is the only supported rendering model, requiring 2+ pages. */ + if (n_pages < 2) + return -EINVAL; + + fb = calloc(1, sizeof(til_fb_t)); + if (!fb) + return -ENOMEM; + + fb->ops = ops; + if (ops->init) { + r = ops->init(settings, &fb->ops_context); + if (r < 0) + goto fail; + } + + for (int i = 0; i < n_pages; i++) + til_fb_page_new(fb); + + fb->n_pages = n_pages; + + pthread_mutex_init(&fb->ready_mutex, NULL); + pthread_cond_init(&fb->ready_cond, NULL); + pthread_mutex_init(&fb->inactive_mutex, NULL); + pthread_cond_init(&fb->inactive_cond, NULL); + pthread_mutex_init(&fb->rebuild_mutex, NULL); + + page = _til_fb_page_get(fb); + if (!page) { + r = -ENOMEM; + goto fail; + } + + r = til_fb_acquire(fb, page); + if (r < 0) + goto fail; + + *res_fb = fb; + + return r; + +fail: + til_fb_free(fb); + + return r; +} + + +/* This informs the fb to reconstruct its pages as they become inactive, + * giving the backend an opportunity to reconfigure them before they get + * rendered to again. It's intended to be used in response to window + * resizes. + */ +void til_fb_rebuild(til_fb_t *fb) +{ + assert(fb); + + /* TODO: this could easily be an atomic counter since we have no need for waiting */ + pthread_mutex_lock(&fb->rebuild_mutex); + fb->rebuild_pages = fb->n_pages; + pthread_mutex_unlock(&fb->rebuild_mutex); +} + + +/* helpers for fragmenting incrementally */ +int til_fb_fragment_slice_single(const til_fb_fragment_t *fragment, unsigned n_fragments, unsigned number, til_fb_fragment_t *res_fragment) +{ + unsigned slice = fragment->height / n_fragments; + unsigned yoff = slice * number; + unsigned pitch; + + if (yoff >= fragment->height) + return 0; + + res_fragment->buf = ((void *)fragment->buf) + yoff * fragment->pitch; + res_fragment->x = fragment->x; + res_fragment->y = yoff; + res_fragment->width = fragment->width; + res_fragment->height = MIN(fragment->height - yoff, slice); + res_fragment->frame_width = fragment->frame_width; + res_fragment->frame_height = fragment->frame_height; + res_fragment->stride = fragment->stride; + res_fragment->pitch = fragment->pitch; + res_fragment->number = number; + res_fragment->zeroed = fragment->zeroed; + + return 1; +} + + +int til_fb_fragment_tile_single(const til_fb_fragment_t *fragment, unsigned tile_size, unsigned number, til_fb_fragment_t *res_fragment) +{ + unsigned w = fragment->width / tile_size, h = fragment->height / tile_size; + unsigned x, y, xoff, yoff; + + if (w * tile_size < fragment->width) + w++; + + if (h * tile_size < fragment->height) + h++; + + y = number / w; + if (y >= h) + return 0; + + x = number - (y * w); + + xoff = x * tile_size; + yoff = y * tile_size; + + res_fragment->buf = (void *)fragment->buf + (yoff * fragment->pitch) + (xoff * 4); + res_fragment->x = fragment->x + xoff; + res_fragment->y = fragment->y + yoff; + res_fragment->width = MIN(fragment->width - xoff, tile_size); + res_fragment->height = MIN(fragment->height - yoff, tile_size); + res_fragment->frame_width = fragment->frame_width; + res_fragment->frame_height = fragment->frame_height; + res_fragment->stride = fragment->stride + ((fragment->width - res_fragment->width) * 4); + res_fragment->pitch = fragment->pitch; + res_fragment->number = number; + + return 1; +} diff --git a/src/til_fb.h b/src/til_fb.h new file mode 100644 index 0000000..792c6e3 --- /dev/null +++ b/src/til_fb.h @@ -0,0 +1,108 @@ +#ifndef _TIL_FB_H +#define _TIL_FB_H + +#include +#include + +#include "til_settings.h" + +/* All renderers should target fb_fragment_t, which may or may not represent + * a full-screen mmap. Helpers are provided for subdividing fragments for + * concurrent renderers. + */ +typedef struct til_fb_fragment_t { + uint32_t *buf; /* pointer to the first pixel in the fragment */ + unsigned x, y; /* absolute coordinates of the upper left corner of this fragment */ + unsigned width, height; /* width and height of this fragment */ + unsigned frame_width; /* width of the frame this fragment is part of */ + unsigned frame_height; /* height of the frame this fragment is part of */ + unsigned stride; /* number of bytes from the end of one row to the start of the next */ + unsigned pitch; /* number of bytes separating y from y + 1, including any padding */ + unsigned number; /* this fragment's number as produced by fragmenting */ + unsigned zeroed:1; /* if this fragment has been zeroed since last flip */ +} til_fb_fragment_t; + +/* This is a page handle object for page flip submission/life-cycle. + * Outside of fb_page_get()/fb_page_put(), you're going to be interested in + * fb_fragment_t. The fragment included here describes the whole page, + * it may be divided via fb_fragment_divide(). + */ +typedef struct til_fb_page_t { + til_fb_fragment_t fragment; +} til_fb_page_t; + +typedef struct til_fb_t til_fb_t; + +/* Supply this struct to fb_new() with the appropriate context */ +typedef struct til_fb_ops_t { + int (*setup)(const til_settings_t *settings, til_setting_desc_t **next); + int (*init)(const til_settings_t *settings, void **res_context); + void (*shutdown)(til_fb_t *fb, void *context); + int (*acquire)(til_fb_t *fb, void *context, void *page); + void (*release)(til_fb_t *fb, void *context); + void * (*page_alloc)(til_fb_t *fb, void *context, til_fb_page_t *res_page); + int (*page_free)(til_fb_t *fb, void *context, void *page); + int (*page_flip)(til_fb_t *fb, void *context, void *page); +} til_fb_ops_t; + +til_fb_page_t * til_fb_page_get(til_fb_t *fb); +void til_fb_page_put(til_fb_t *fb, til_fb_page_t *page); +til_fb_t * til_fb_free(til_fb_t *fb); +void til_fb_get_put_pages_count(til_fb_t *fb, unsigned *count); +int til_fb_new(const til_fb_ops_t *ops, til_settings_t *settings, int n_pages, til_fb_t **res_fb); +void til_fb_rebuild(til_fb_t *fb); +void * til_fb_context(til_fb_t *fb); +int til_fb_flip(til_fb_t *fb); +void til_fb_fragment_divide(til_fb_fragment_t *fragment, unsigned n_fragments, til_fb_fragment_t fragments[]); +int til_fb_fragment_slice_single(const til_fb_fragment_t *fragment, unsigned n_fragments, unsigned num, til_fb_fragment_t *res_fragment); +int til_fb_fragment_tile_single(const til_fb_fragment_t *fragment, unsigned tile_size, unsigned num, til_fb_fragment_t *res_fragment); + + +/* checks if a coordinate is contained within a fragment */ +static inline int til_fb_fragment_contains(til_fb_fragment_t *fragment, int x, int y) +{ + if (x < fragment->x || x >= fragment->x + fragment->width || + y < fragment->y || y >= fragment->y + fragment->height) + return 0; + + return 1; +} + + +/* puts a pixel into the fragment, no bounds checking is performed. */ +static inline void til_fb_fragment_put_pixel_unchecked(til_fb_fragment_t *fragment, int x, int y, uint32_t pixel) +{ + uint32_t *pixels = ((void *)fragment->buf) + (y - fragment->y) * fragment->pitch; + + pixels[x - fragment->x] = pixel; +} + + +/* puts a pixel into the fragment, bounds checking is performed with a draw performed return status */ +static inline int til_fb_fragment_put_pixel_checked(til_fb_fragment_t *fragment, int x, int y, uint32_t pixel) +{ + if (!til_fb_fragment_contains(fragment, x, y)) + return 0; + + til_fb_fragment_put_pixel_unchecked(fragment, x, y, pixel); + + return 1; +} + + +/* zero a fragment */ +static inline void til_fb_fragment_zero(til_fb_fragment_t *fragment) +{ + void *buf = fragment->buf; + + if (fragment->zeroed) + return; + + /* TODO: there should be a fast-path for non-divided fragments where there's no stride to skip */ + for (int y = 0; y < fragment->height; y++, buf += fragment->pitch) + memset(buf, 0, fragment->pitch - fragment->stride); + + fragment->zeroed = 1; +} + +#endif diff --git a/src/til_knobs.h b/src/til_knobs.h new file mode 100644 index 0000000..370be27 --- /dev/null +++ b/src/til_knobs.h @@ -0,0 +1,91 @@ +#ifndef _TIL_KNOBS_H +#define _TIL_KNOBS_H + +#include + +/* A knob exposes a binding for some float in a module's context + * which can be varied at runtime between frames to influence + * the output. There's some overlap with settings, but settings + * are more intended for configuration applied at context + * creation, which won't vary frame-to-frame, but may influence + * the initial value and/or automatic behavior of knobs for + * instance, or even which knobs are available. + * + * At this time knobs will only apply to floats, accompanied by + * some rudimentary bounds. + * + * Integer types would probably be useful, and maybe a precision + * specifier, those can be added in the future as needed, but I'd + * like to keep it simple for now and see what kind of problems + * emerge. + * + * The current expectation is that a module context struct will + * incorporate an array of knobs, replacing loose floats already + * being automatically varied within the module frame-to-frame. + * + * The module will then use the knob_auto_* helpers below to + * access and manipulate the values, instead of directly + * accessing the loose floats as before. + * + * External manipulators of the knobs will use the knob_* + * helpers, instead of the knob_auto_* helpers, to + * access+manipulate the knobs. These helpers are basically just + * to get external and internal manipulators to agree on which + * side owns control via the managed field. + */ +typedef struct til_knob_t { + const char *name; /* Short API-oriented name */ + const char *desc; /* Longer UI-oriented name */ + const float min, max; /* Value bounds */ + float value; /* Value knob affects */ + unsigned managed:1; /* Set when knob control of value is active, + * suppress automagic control of value when set. + */ +} til_knob_t; + + +/* helper for modules automating knob controls, use this to + * change values intead of direct manipulation to respect active. + * returns new (or unchanged) value + */ +static inline float til_knob_auto_set(til_knob_t *knob, float value) +{ + assert(knob); + + if (knob->managed) + return knob->value; + + return knob->value = value; +} + +/* identical to knob_auto_set, except adds to existing value. + */ +static inline float til_knob_auto_add(til_knob_t *knob, float value) +{ + assert(knob); + + return til_knob_auto_set(knob, knob->value + value); +} + + +/* identical to knob_auto* variants, except intended for + * external knob-twisters, i.e. the "managed" knob entrypoints. + */ +static inline float til_knob_set(til_knob_t *knob, float value) +{ + assert(knob); + + knob->managed = 1; + + return knob->value = value; +} + + +static inline float til_knob_add(til_knob_t *knob, float value) +{ + assert(knob); + + return til_knob_set(knob, knob->value + value); +} + +#endif diff --git a/src/til_settings.c b/src/til_settings.c new file mode 100644 index 0000000..e3c8c6c --- /dev/null +++ b/src/til_settings.c @@ -0,0 +1,388 @@ +#include +#include +#include +#include +#include + +#include "til_settings.h" +#include "til_util.h" + +#ifdef __WIN32__ +char * strndup(const char *s, size_t n) +{ + size_t len; + char *buf; + + for (len = 0; len < n; len++) { + if (!s[len]) + break; + } + + buf = calloc(len + 1, sizeof(char)); + if (!buf) + return NULL; + + memcpy(buf, s, len); + + return buf; +} +#endif + +/* Split form of key=value[,key=value...] settings string */ +typedef struct til_settings_t { + unsigned num; + const char **keys; + const char **values; +} til_settings_t; + +typedef enum til_settings_fsm_state_t { + TIL_SETTINGS_FSM_STATE_KEY, + TIL_SETTINGS_FSM_STATE_EQUAL, + TIL_SETTINGS_FSM_STATE_VALUE, + TIL_SETTINGS_FSM_STATE_COMMA, +} til_settings_fsm_state_t; + + +static int add_value(til_settings_t *settings, const char *key, const char *value) +{ + assert(settings); + + settings->num++; + /* TODO errors */ + settings->keys = realloc(settings->keys, settings->num * sizeof(const char **)); + settings->values = realloc(settings->values, settings->num * sizeof(const char **)); + settings->keys[settings->num - 1] = key; + settings->values[settings->num - 1] = value; + + return 0; +} + + +/* split settings_string into a data structure */ +til_settings_t * til_settings_new(const char *settings_string) +{ + til_settings_fsm_state_t state = TIL_SETTINGS_FSM_STATE_KEY; + const char *p, *token; + til_settings_t *settings; + + settings = calloc(1, sizeof(til_settings_t)); + if (!settings) + return NULL; + + if (!settings_string) + return settings; + + /* TODO: unescaping? */ + for (token = p = settings_string; ;p++) { + + switch (state) { + case TIL_SETTINGS_FSM_STATE_COMMA: + token = p; + state = TIL_SETTINGS_FSM_STATE_KEY; + break; + + case TIL_SETTINGS_FSM_STATE_KEY: + if (*p == '=' || *p == ',' || *p == '\0') { + add_value(settings, strndup(token, p - token), NULL); + + if (*p == '=') + state = TIL_SETTINGS_FSM_STATE_EQUAL; + else if (*p == ',') + state = TIL_SETTINGS_FSM_STATE_COMMA; + } + break; + + case TIL_SETTINGS_FSM_STATE_EQUAL: + token = p; + state = TIL_SETTINGS_FSM_STATE_VALUE; + break; + + case TIL_SETTINGS_FSM_STATE_VALUE: + if (*p == ',' || *p == '\0') { + settings->values[settings->num - 1] = strndup(token, p - token); + state = TIL_SETTINGS_FSM_STATE_COMMA; + } + break; + + default: + assert(0); + } + + if (*p == '\0') + break; + } + + /* FIXME: this should probably never leave a value or key entry NULL */ + + return settings; +} + + +/* free structure attained via settings_new() */ +til_settings_t * til_settings_free(til_settings_t *settings) +{ + + if (settings) { + for (unsigned i = 0; i < settings->num; i++) { + free((void *)settings->keys[i]); + free((void *)settings->values[i]); + } + + free((void *)settings->keys); + free((void *)settings->values); + free(settings); + } + + return NULL; +} + + +/* find key= in settings, return dup of value side or NULL if missing */ +const char * til_settings_get_value(const til_settings_t *settings, const char *key) +{ + assert(settings); + assert(key); + + for (int i = 0; i < settings->num; i++) { + if (!strcmp(key, settings->keys[i])) + return settings->values[i]; + } + + return NULL; +} + + +/* return positional key from settings */ +const char * til_settings_get_key(const til_settings_t *settings, unsigned pos) +{ + assert(settings); + + if (pos < settings->num) + return settings->keys[pos]; + + return NULL; +} + + +/* add key=value to the settings, + * or just key if value is NULL. + */ +/* returns < 0 on error */ +int til_settings_add_value(til_settings_t *settings, const char *key, const char *value) +{ + assert(settings); + assert(key); + + return add_value(settings, strdup(key), value ? strdup(value) : NULL); +} + + +/* apply the supplied setting description generators to the supplied settings */ +/* returns 0 when input settings are complete */ +/* returns 1 when input settings are incomplete, storing the next setting's description needed in *next_setting */ +/* returns -errno on error */ +int til_settings_apply_desc_generators(const til_settings_t *settings, const til_setting_desc_generator_t generators[], unsigned n_generators, void *setup_context, til_setting_desc_t **next_setting) +{ + til_setting_desc_t *next; + + assert(settings); + assert(generators); + assert(n_generators > 0); + assert(next_setting); + + for (unsigned i = 0; i < n_generators; i++) { + const til_setting_desc_generator_t *g = &generators[i]; + const char *value; + til_setting_desc_t *desc; + int r; + + r = g->func(setup_context, &desc); + if (r < 0) + return r; + + assert(desc); + + value = til_settings_get_value(settings, g->key); + if (value) { + int r; + + r = til_setting_desc_check(desc, value); + til_setting_desc_free(desc); + if (r < 0) + return r; + + if (g->value_ptr) + *g->value_ptr = value; + + continue; + } + + *next_setting = desc; + + return 1; + } + + return 0; +} + + +/* convenience helper for creating a new setting description */ +/* copies of everything supplied are made in newly allocated memory, stored @ res_desc */ +/* returns < 0 on error */ +int til_setting_desc_clone(const til_setting_desc_t *desc, til_setting_desc_t **res_desc) +{ + til_setting_desc_t *d; + + assert(desc); + assert(desc->name); + assert(desc->preferred); /* XXX: require a preferred default? */ + assert(!desc->annotations || desc->values); + assert(res_desc); + + d = calloc(1, sizeof(til_setting_desc_t)); + if (!d) + return -ENOMEM; + + d->name = strdup(desc->name); + if (desc->key) /* This is inappropriately subtle, but when key is NULL, the value will be the key, and there will be no value side at all. */ + d->key = strdup(desc->key); + if (desc->regex) + d->regex = strdup(desc->regex); + + d->preferred = strdup(desc->preferred); + + if (desc->values) { + unsigned i; + + for (i = 0; desc->values[i]; i++); + + d->values = calloc(i + 1, sizeof(*desc->values)); + + if (desc->annotations) + d->annotations = calloc(i + 1, sizeof(*desc->annotations)); + + for (i = 0; desc->values[i]; i++) { + d->values[i] = strdup(desc->values[i]); + + if (desc->annotations) { + assert(desc->annotations[i]); + d->annotations[i] = strdup(desc->annotations[i]); + } + } + } + + d->random = desc->random; + + /* TODO: handle allocation errors above... */ + *res_desc = d; + + return 0; +} + + +til_setting_desc_t * til_setting_desc_free(til_setting_desc_t *desc) +{ + if (desc) { + free((void *)desc->name); + free((void *)desc->key); + free((void *)desc->regex); + free((void *)desc->preferred); + + if (desc->values) { + for (unsigned i = 0; desc->values[i]; i++) { + free((void *)desc->values[i]); + + if (desc->annotations) + free((void *)desc->annotations[i]); + } + + free((void *)desc->values); + free((void *)desc->annotations); + } + + free(desc); + } + + return NULL; +} + + +int til_setting_desc_check(const til_setting_desc_t *desc, const char *value) +{ + assert(desc); + + if (desc->values) { + + for (int i = 0; desc->values[i]; i++) { + if (!strcasecmp(desc->values[i], value)) + return 0; + } + + return -EINVAL; + } + + /* TODO: apply regex check */ + + return 0; +} + + +/* wrapper around sprintf for convenient buffer size computation */ +/* supply NULL buf when computing size, size and offset are ignored. + * supply non-NULL for actual writing into buf of size bytes @ offset. + * return value is number of bytes (potentially if !buf) written + */ +static int snpf(char *buf, size_t size, off_t offset, const char *format, ...) +{ + size_t avail = 0; + va_list ap; + int r; + + if (buf) { + assert(size > offset); + + avail = size - offset; + buf += offset; + } + + va_start(ap, format); + r = vsnprintf(buf, avail, format, ap); + va_end(ap); + + return r; +} + + +char * til_settings_as_arg(const til_settings_t *settings) +{ + char *buf = NULL; + size_t off, size; + + /* intentionally avoided open_memstream for portability reasons */ + for (;;) { + unsigned i; + + for (i = off = 0; i < settings->num; i++) { + if (i > 0) + off += snpf(buf, size, off, ","); + + off += snpf(buf, size, off, "%s", settings->keys[i]); + + if (settings->values[i]) + off += snpf(buf, size, off, "=%s", settings->values[i]); + } + + if (!buf) { + size = off + 1; + buf = calloc(size, sizeof(char)); + if (!buf) + return NULL; + + continue; + } + + break; + } + + return buf; +} diff --git a/src/til_settings.h b/src/til_settings.h new file mode 100644 index 0000000..935aa5b --- /dev/null +++ b/src/til_settings.h @@ -0,0 +1,43 @@ +#ifndef _TIL_SETTINGS_H +#define _TIL_SETTINGS_H + +#include + +/* Individual setting description */ +typedef struct til_setting_desc_t { + const char *name; /* long-form/human name for setting */ + const char *key; /* short-form/key for setting, used as left side of =value in settings string */ + const char *regex; /* value must conform to this regex */ + const char *preferred; /* if there's a default, this is it */ + const char **values; /* if a set of values is provided, listed here */ + const char **annotations; /* if a set of values is provided, annotations for those values may be listed here */ + char * (*random)(void);/* if set, returns a valid random value for this setting */ +} til_setting_desc_t; + +/* For conveniently representing setting description generators */ +typedef struct til_setting_desc_generator_t { + const char *key; /* key this generator applies to */ + const char **value_ptr; /* where to put the value */ + int (*func)(void *setup_context, til_setting_desc_t **res_desc); +} til_setting_desc_generator_t; + +typedef struct til_settings_t til_settings_t; + +til_settings_t * til_settings_new(const char *settings); +til_settings_t * til_settings_free(til_settings_t *settings); +const char * til_settings_get_value(const til_settings_t *settings, const char *key); +const char * til_settings_get_key(const til_settings_t *settings, unsigned pos); +int til_settings_add_value(til_settings_t *settings, const char *key, const char *value); +char * til_settings_as_arg(const til_settings_t *settings); +int til_settings_apply_desc_generators(const til_settings_t *settings, const til_setting_desc_generator_t generators[], unsigned n_generators, void *setup_context, til_setting_desc_t **next_setting); + +int til_setting_desc_clone(const til_setting_desc_t *desc, til_setting_desc_t **res_desc); +til_setting_desc_t * til_setting_desc_free(til_setting_desc_t *desc); +int til_setting_desc_check(const til_setting_desc_t *desc, const char *value); + +#ifndef TIL_SETTINGS_STR +#define _TIL_SETTINGS_STR(s) #s +#define TIL_SETTINGS_STR(s) _TIL_SETTINGS_STR(s) +#endif + +#endif diff --git a/src/til_threads.c b/src/til_threads.c new file mode 100644 index 0000000..7c68d52 --- /dev/null +++ b/src/til_threads.c @@ -0,0 +1,166 @@ +#include +#include +#include + +#include "til.h" +#include "til_fb.h" +#include "til_threads.h" +#include "til_util.h" + +typedef struct til_thread_t { + til_threads_t *threads; + pthread_t pthread; + unsigned id; +} til_thread_t; + +typedef struct til_threads_t { + unsigned n_threads; + + pthread_mutex_t idle_mutex; + pthread_cond_t idle_cond; + unsigned n_idle; + + pthread_mutex_t frame_mutex; + pthread_cond_t frame_cond; + void (*render_fragment_func)(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment); + void *context; + til_fb_fragment_t *fragment; + til_fragmenter_t fragmenter; + unsigned ticks; + + unsigned next_fragment; + unsigned frame_num; + + til_thread_t threads[]; +} til_threads_t; + + +/* render fragments using the supplied render function */ +static void * thread_func(void *_thread) +{ + til_thread_t *thread = _thread; + til_threads_t *threads = thread->threads; + unsigned prev_frame_num = 0; + + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + for (;;) { + + /* wait for a new frame */ + pthread_mutex_lock(&threads->frame_mutex); + pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, &threads->frame_mutex); + while (threads->frame_num == prev_frame_num) + pthread_cond_wait(&threads->frame_cond, &threads->frame_mutex); + prev_frame_num = threads->frame_num; + pthread_cleanup_pop(1); + + /* render fragments */ + for (;;) { + unsigned frag_num; + til_fb_fragment_t fragment; + + frag_num = __sync_fetch_and_add(&threads->next_fragment, 1); + + if (!threads->fragmenter(threads->context, threads->fragment, frag_num, &fragment)) + break; + + threads->render_fragment_func(threads->context, threads->ticks, thread->id, &fragment); + } + + /* report as idle */ + pthread_mutex_lock(&threads->idle_mutex); + pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, &threads->idle_mutex); + threads->n_idle++; + if (threads->n_idle == threads->n_threads) /* Frame finished! Notify potential waiter. */ + pthread_cond_signal(&threads->idle_cond); + pthread_cleanup_pop(1); + } + + return NULL; +} + + +/* wait for all threads to be idle */ +void til_threads_wait_idle(til_threads_t *threads) +{ + pthread_mutex_lock(&threads->idle_mutex); + pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, &threads->idle_mutex); + while (threads->n_idle < threads->n_threads) + pthread_cond_wait(&threads->idle_cond, &threads->idle_mutex); + pthread_cleanup_pop(1); +} + + +/* submit a frame's fragments to the threads */ +void til_threads_frame_submit(til_threads_t *threads, til_fb_fragment_t *fragment, til_fragmenter_t fragmenter, void (*render_fragment_func)(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment), void *context, unsigned ticks) +{ + til_threads_wait_idle(threads); /* XXX: likely non-blocking; already happens pre page flip */ + + pthread_mutex_lock(&threads->frame_mutex); + pthread_cleanup_push((void (*)(void *))pthread_mutex_unlock, &threads->frame_mutex); + threads->fragment = fragment; + threads->fragmenter = fragmenter; + threads->render_fragment_func = render_fragment_func; + threads->context = context; + threads->ticks = ticks; + threads->frame_num++; + threads->n_idle = threads->next_fragment = 0; + pthread_cond_broadcast(&threads->frame_cond); + pthread_cleanup_pop(1); +} + + +/* create threads instance, a thread per cpu is created */ +til_threads_t * til_threads_create(void) +{ + unsigned num = til_get_ncpus(); + til_threads_t *threads; + + threads = calloc(1, sizeof(til_threads_t) + sizeof(til_thread_t) * num); + if (!threads) + return NULL; + + threads->n_idle = threads->n_threads = num; + + pthread_mutex_init(&threads->idle_mutex, NULL); + pthread_cond_init(&threads->idle_cond, NULL); + + pthread_mutex_init(&threads->frame_mutex, NULL); + pthread_cond_init(&threads->frame_cond, NULL); + + for (unsigned i = 0; i < num; i++) { + til_thread_t *thread = &threads->threads[i]; + + thread->threads = threads; + thread->id = i; + pthread_create(&thread->pthread, NULL, thread_func, thread); + } + + return threads; +} + + +/* destroy a threads instance */ +void til_threads_destroy(til_threads_t *threads) +{ + for (unsigned i = 0; i < threads->n_threads; i++) + pthread_cancel(threads->threads[i].pthread); + + for (unsigned i = 0; i < threads->n_threads; i++) + pthread_join(threads->threads[i].pthread, NULL); + + pthread_mutex_destroy(&threads->idle_mutex); + pthread_cond_destroy(&threads->idle_cond); + + pthread_mutex_destroy(&threads->frame_mutex); + pthread_cond_destroy(&threads->frame_cond); + + free(threads); +} + + +/* return the number of threads */ +unsigned til_threads_num_threads(til_threads_t *threads) +{ + return threads->n_threads; +} diff --git a/src/til_threads.h b/src/til_threads.h new file mode 100644 index 0000000..b55d7b8 --- /dev/null +++ b/src/til_threads.h @@ -0,0 +1,14 @@ +#ifndef _TIL_THREADS_H +#define _TIL_THREADS_H + +typedef struct til_fb_fragment_t til_fb_fragment_t; +typedef struct til_threads_t til_threads_t; + +til_threads_t * til_threads_create(); +void til_threads_destroy(til_threads_t *threads); + +void til_threads_frame_submit(til_threads_t *threads, til_fb_fragment_t *fragment, til_fragmenter_t fragmenter, void (*render_fragment_func)(void *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment), void *context, unsigned ticks); +void til_threads_wait_idle(til_threads_t *threads); +unsigned til_threads_num_threads(til_threads_t *threads); + +#endif diff --git a/src/til_util.c b/src/til_util.c new file mode 100644 index 0000000..e9b1021 --- /dev/null +++ b/src/til_util.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +#ifdef __WIN32__ +#include +#endif + +#include "til_util.h" + +#define TIL_SYSFS_CPU "/sys/devices/system/cpu/cpu" +#define TIL_MAXCPUS 1024 + +unsigned til_get_ncpus(void) +{ +#ifdef __WIN32__ + SYSTEM_INFO sysinfo; + + GetSystemInfo(&sysinfo); + + return sysinfo.dwNumberOfProcessors; +#else + char path[cstrlen(TIL_SYSFS_CPU "1024") + 1]; + unsigned n; + + for (n = 0; n < TIL_MAXCPUS; n++) { + snprintf(path, sizeof(path), "%s%u", TIL_SYSFS_CPU, n); + if (access(path, F_OK) == -1) + break; + } + + return n == 0 ? 1 : n; +#endif +} diff --git a/src/til_util.h b/src/til_util.h new file mode 100644 index 0000000..cea1825 --- /dev/null +++ b/src/til_util.h @@ -0,0 +1,32 @@ +#ifndef _TIL_UTIL_H +#define _TIL_UTIL_H + +#include +#include +#include +#include + +#define exit_if(_cond, _fmt, ...) \ + if (_cond) { \ + fprintf(stderr, "Fatal error: " _fmt "\n", ##__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } + +#define pexit_if(_cond, _fmt, ...) \ + exit_if(_cond, _fmt ": %s", ##__VA_ARGS__, strerror(errno)) + +#define nelems(_array) \ + (sizeof(_array) / sizeof(_array[0])) + +#define cstrlen(_str) \ + (sizeof(_str) - 1) + +#define MIN(_a, _b) \ + ((_a) < (_b) ? (_a) : (_b)) + +#define MAX(_a, _b) \ + ((_a) > (_b) ? (_a) : (_b)) + +unsigned til_get_ncpus(void); + +#endif /* _TIL_UTIL_H */ diff --git a/src/util.c b/src/util.c deleted file mode 100644 index 500ac75..0000000 --- a/src/util.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include -#include - -#ifdef __WIN32__ -#include -#endif - -#include "util.h" - -#define SYSFS_CPU "/sys/devices/system/cpu/cpu" -#define MAXCPUS 1024 - -unsigned get_ncpus(void) -{ -#ifdef __WIN32__ - SYSTEM_INFO sysinfo; - - GetSystemInfo(&sysinfo); - - return sysinfo.dwNumberOfProcessors; -#else - char path[cstrlen(SYSFS_CPU "1024") + 1]; - unsigned n; - - for (n = 0; n < MAXCPUS; n++) { - snprintf(path, sizeof(path), "%s%u", SYSFS_CPU, n); - if (access(path, F_OK) == -1) - break; - } - - return n == 0 ? 1 : n; -#endif -} diff --git a/src/util.h b/src/util.h deleted file mode 100644 index df455a3..0000000 --- a/src/util.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _UTIL_H -#define _UTIL_H - -#include -#include -#include -#include - -#define exit_if(_cond, _fmt, ...) \ - if (_cond) { \ - fprintf(stderr, "Fatal error: " _fmt "\n", ##__VA_ARGS__); \ - exit(EXIT_FAILURE); \ - } - -#define pexit_if(_cond, _fmt, ...) \ - exit_if(_cond, _fmt ": %s", ##__VA_ARGS__, strerror(errno)) - -#define nelems(_array) \ - (sizeof(_array) / sizeof(_array[0])) - -#define cstrlen(_str) \ - (sizeof(_str) - 1) - -#define MIN(_a, _b) \ - ((_a) < (_b) ? (_a) : (_b)) - -#define MAX(_a, _b) \ - ((_a) > (_b) ? (_a) : (_b)) - -unsigned get_ncpus(void); - -#endif /* _UTIL_H */ -- cgit v1.2.1