summaryrefslogtreecommitdiff
path: root/src/rototiller.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rototiller.c')
-rw-r--r--src/rototiller.c345
1 files changed, 32 insertions, 313 deletions
diff --git a/src/rototiller.c b/src/rototiller.c
index 84898da..18f0376 100644
--- a/src/rototiller.c
+++ b/src/rototiller.c
@@ -11,27 +11,16 @@
#include <unistd.h>
#include "settings.h"
-#include "setup.h"
#include "fb.h"
-#include "fps.h"
#include "rototiller.h"
#include "threads.h"
#include "util.h"
/* Copyright (C) 2016 Vito Caputo <vcaputo@pengaru.com> */
-#define NUM_FB_PAGES 3
-/* ^ By triple-buffering, we can have a page tied up being displayed, another
- * tied up submitted and waiting for vsync, and still not block on getting
- * another page so we can begin rendering another frame before vsync. With
- * just two pages we end up twiddling thumbs until the vsync arrives.
- */
#define DEFAULT_MODULE "rtv"
-#define DEFAULT_VIDEO "sdl"
-extern fb_ops_t drm_fb_ops;
-extern fb_ops_t sdl_fb_ops;
-fb_ops_t *fb_ops;
+static threads_t *rototiller_threads;
extern rototiller_module_t compose_module;
extern rototiller_module_t drizzle_module;
@@ -75,17 +64,21 @@ static const rototiller_module_t *modules[] = {
&swarm_module,
};
-typedef struct rototiller_t {
- const rototiller_module_t *module;
- void *module_context;
- threads_t *threads;
- pthread_t thread;
- fb_t *fb;
- struct timeval start_tv;
- unsigned ticks_offset;
-} rototiller_t;
-static rototiller_t rototiller;
+/* initialize rototiller (create rendering threads) */
+int rototiller_init(void)
+{
+ if (!(rototiller_threads = threads_create()))
+ return -errno;
+
+ return 0;
+}
+
+
+void rototiller_shutdown(void)
+{
+ threads_destroy(rototiller_threads);
+}
const rototiller_module_t * rototiller_lookup_module(const char *name)
@@ -113,6 +106,10 @@ void rototiller_get_modules(const rototiller_module_t ***res_modules, size_t *re
static void module_render_fragment(const rototiller_module_t *module, void *context, threads_t *threads, unsigned ticks, fb_fragment_t *fragment)
{
+ assert(module);
+ assert(threads);
+ assert(fragment);
+
if (module->prepare_frame) {
rototiller_fragmenter_t fragmenter;
@@ -136,114 +133,31 @@ static void module_render_fragment(const rototiller_module_t *module, void *cont
*/
void rototiller_module_render(const rototiller_module_t *module, void *context, unsigned ticks, fb_fragment_t *fragment)
{
- module_render_fragment(module, context, rototiller.threads, ticks, fragment);
+ module_render_fragment(module, context, rototiller_threads, ticks, fragment);
}
-
-typedef struct argv_t {
- const char *module;
- const char *video;
-
- unsigned use_defaults:1;
- unsigned help:1;
-} argv_t;
-
-/*
- * ./rototiller --video=drm,dev=/dev/dri/card3,connector=VGA-1,mode=640x480@60
- * ./rototiller --video=sdl,size=640x480
- * ./rototiller --module=roto,foo=bar,module=settings
- * ./rototiller --defaults
- */
-static int parse_argv(int argc, const char *argv[], argv_t *res_args)
+int rototiller_module_create_context(const rototiller_module_t *module, unsigned ticks, void **res_context)
{
- int i;
-
- assert(argc > 0);
- assert(argv);
- assert(res_args);
-
- /* this is intentionally being kept very simple, no new dependencies like getopt. */
-
- for (i = 1; i < argc; i++) {
- if (!strncmp("--video=", argv[i], 8)) {
- res_args->video = &argv[i][8];
- } else if (!strncmp("--module=", argv[i], 9)) {
- res_args->module = &argv[i][9];
- } else if (!strcmp("--defaults", argv[i])) {
- res_args->use_defaults = 1;
- } else if (!strcmp("--help", argv[i])) {
- res_args->help = 1;
- } else {
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
+ void *context;
-typedef struct setup_t {
- settings_t *module;
- settings_t *video;
-} setup_t;
+ assert(module);
+ assert(res_context);
-/* FIXME: this is unnecessarily copy-pasta, i think modules should just be made
- * more generic to encompass the setting up uniformly, then basically
- * subclass the video backend vs. renderer stuff.
- */
+ if (!module->create_context)
+ return 0;
-/* select video backend if not yet selected, then setup the selected backend. */
-static int setup_video(settings_t *settings, setting_desc_t **next_setting)
-{
- const char *video;
-
- /* XXX: there's only one option currently, so this is simple */
- video = settings_get_key(settings, 0);
- if (!video) {
- setting_desc_t *desc;
- const char *values[] = {
-#ifdef HAVE_DRM
- "drm",
-#endif
- "sdl",
- NULL,
- };
- int r;
-
- r = setting_desc_clone(&(setting_desc_t){
- .name = "Video Backend",
- .key = NULL,
- .regex = "[a-z]+",
- .preferred = DEFAULT_VIDEO,
- .values = values,
- .annotations = NULL
- }, next_setting);
- if (r < 0)
- return r;
-
- return 1;
- }
-
- /* XXX: this is kind of hacky for now */
-#ifdef HAVE_DRM
- if (!strcmp(video, "drm")) {
- fb_ops = &drm_fb_ops;
-
- return drm_fb_ops.setup(settings, next_setting);
- } else
-#endif
- if (!strcmp(video, "sdl")) {
- fb_ops = &sdl_fb_ops;
+ context = module->create_context(ticks, threads_num_threads(rototiller_threads));
+ if (!context)
+ return -ENOMEM;
- return sdl_fb_ops.setup(settings, next_setting);
- }
+ *res_context = context;
- return -EINVAL;
+ return 0;
}
/* select module if not yet selected, then setup the module. */
-static int setup_module(settings_t *settings, setting_desc_t **next_setting)
+int rototiller_module_setup(settings_t *settings, setting_desc_t **next_setting)
{
const rototiller_module_t *module;
const char *name;
@@ -284,198 +198,3 @@ static int setup_module(settings_t *settings, setting_desc_t **next_setting)
return 0;
}
-
-
-/* turn args into settings, automatically applying defaults if appropriate, or interactively if appropriate. */
-/* returns negative value on error, 0 when settings unchanged from args, 1 when changed */
-static int setup_from_args(argv_t *args, setup_t *res_setup)
-{
- int r, changes = 0;
- setup_t setup;
-
- setup.module = settings_new(args->module);
- if (!setup.module)
- return -ENOMEM;
-
- setup.video = settings_new(args->video);
- if (!setup.video) {
- settings_free(setup.module);
-
- return -ENOMEM;
- }
-
- r = setup_interactively(setup.module, setup_module, args->use_defaults);
- if (r < 0) {
- settings_free(setup.module);
- settings_free(setup.video);
-
- return r;
- }
-
- if (r)
- changes = 1;
-
- r = setup_interactively(setup.video, setup_video, args->use_defaults);
- if (r < 0) {
- settings_free(setup.module);
- settings_free(setup.video);
-
- return r;
- }
-
- if (r)
- changes = 1;
-
- *res_setup = setup;
-
- return changes;
-}
-
-
-static int print_setup_as_args(setup_t *setup)
-{
- char *module_args, *video_args;
- char buf[64];
- int r;
-
- module_args = settings_as_arg(setup->module);
- if (!module_args) {
- r = -ENOMEM;
-
- goto _out;
- }
-
- video_args = settings_as_arg(setup->video);
- if (!video_args) {
- r = -ENOMEM;
-
- goto _out_module;
- }
-
- r = printf("\nConfigured settings as flags:\n --module=%s --video=%s\n\nPress enter to continue...\n",
- module_args,
- video_args);
-
- if (r < 0)
- goto _out_video;
-
- (void) fgets(buf, sizeof(buf), stdin);
-
-_out_video:
- free(video_args);
-_out_module:
- free(module_args);
-_out:
- return r;
-}
-
-
-static int print_help(void)
-{
- return printf(
- "Run without any flags or partial settings for interactive mode.\n"
- "\n"
- "Supported flags:\n"
- " --defaults use defaults for unspecified settings\n"
- " --help this help\n"
- " --module= module settings\n"
- " --video= video settings\n"
- );
-}
-
-
-static unsigned get_ticks(const struct timeval *start, const struct timeval *now, unsigned offset)
-{
- return (unsigned)((now->tv_sec - start->tv_sec) * 1000 + (now->tv_usec - start->tv_usec) / 1000) + offset;
-}
-
-
-static void * rototiller_thread(void *_rt)
-{
- rototiller_t *rt = _rt;
- struct timeval now;
-
- for (;;) {
- fb_page_t *page;
- unsigned ticks;
-
- page = fb_page_get(rt->fb);
-
- gettimeofday(&now, NULL);
- ticks = get_ticks(&rt->start_tv, &now, rt->ticks_offset);
-
- module_render_fragment(rt->module, rt->module_context, rt->threads, ticks, &page->fragment);
-
- fb_page_put(rt->fb, page);
- }
-
- return NULL;
-}
-
-
-/* When run with partial/no arguments, if stdin is a tty, enter an interactive setup.
- * If stdin is not a tty, or if --defaults is supplied in argv, default settings are used.
- * If any changes to the settings occur in the course of execution, either interactively or
- * throught --defaults, then print out the explicit CLI invocation usable for reproducing
- * the invocation.
- */
-int main(int argc, const char *argv[])
-{
- setup_t setup = {};
- argv_t args = {};
- int r;
-
- exit_if(parse_argv(argc, argv, &args) < 0,
- "unable to process arguments");
-
- if (args.help)
- return print_help() < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-
- exit_if((r = setup_from_args(&args, &setup)) < 0,
- "unable to setup: %s", strerror(-r));
-
- exit_if(r && print_setup_as_args(&setup) < 0,
- "unable to print setup");
-
- exit_if(!(rototiller.module = rototiller_lookup_module(settings_get_key(setup.module, 0))),
- "unable to lookup module from settings \"%s\"", settings_get_key(setup.module, 0));
-
- exit_if((r = fb_new(fb_ops, setup.video, NUM_FB_PAGES, &rototiller.fb)) < 0,
- "unable to create fb: %s", strerror(-r));
-
- exit_if(!fps_setup(),
- "unable to setup fps counter");
-
- pexit_if(!(rototiller.threads = threads_create()),
- "unable to create rendering threads");
-
- gettimeofday(&rototiller.start_tv, NULL);
- exit_if(rototiller.module->create_context &&
- !(rototiller.module_context = rototiller.module->create_context(
- get_ticks(&rototiller.start_tv,
- &rototiller.start_tv,
- rototiller.ticks_offset),
- threads_num_threads(rototiller.threads))),
- "unable to create module context");
-
- pexit_if(pthread_create(&rototiller.thread, NULL, rototiller_thread, &rototiller) != 0,
- "unable to create dispatch thread");
-
- for (;;) {
- if (fb_flip(rototiller.fb) < 0)
- break;
-
- fps_print(rototiller.fb);
- }
-
- pthread_cancel(rototiller.thread);
- pthread_join(rototiller.thread, NULL);
- threads_destroy(rototiller.threads);
-
- if (rototiller.module_context)
- rototiller.module->destroy_context(rototiller.module_context);
-
- fb_free(rototiller.fb);
-
- return EXIT_SUCCESS;
-}
© All Rights Reserved