summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/drm_fb.c372
-rw-r--r--src/drmsetup.c162
-rw-r--r--src/drmsetup.h10
-rw-r--r--src/fb.c12
-rw-r--r--src/fb.h7
-rw-r--r--src/rototiller.c250
7 files changed, 598 insertions, 217 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index acb5c16..a9cee3e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
SUBDIRS = modules
bin_PROGRAMS = rototiller
-rototiller_SOURCES = drmsetup.c drmsetup.h drm_fb.c drm_fb.h fb.c fb.h fps.c fps.h rototiller.c rototiller.h settings.h settings.c setup.h setup.c threads.c threads.h util.c util.h
+rototiller_SOURCES = drm_fb.c drm_fb.h fb.c fb.h fps.c fps.h rototiller.c rototiller.h settings.h settings.c setup.h setup.c threads.c threads.h util.c util.h
rototiller_LDADD = @ROTOTILLER_LIBS@ -lm modules/julia/libjulia.a modules/plasma/libplasma.a modules/ray/libray.a modules/roto/libroto.a modules/sparkler/libsparkler.a modules/stars/libstars.a
rototiller_CPPFLAGS = @ROTOTILLER_CFLAGS@
diff --git a/src/drm_fb.c b/src/drm_fb.c
index 99169de..855fce1 100644
--- a/src/drm_fb.c
+++ b/src/drm_fb.c
@@ -1,25 +1,28 @@
+#define _GNU_SOURCE /* for asprintf() */
+#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include "fb.h"
+#include "settings.h"
#include "util.h"
-
/* drm fb backend, everything drm-specific in rototiller resides here. */
typedef struct drm_fb_t {
int drm_fd;
- uint32_t crtc_id;
- uint32_t *connectors;
- int n_connectors;
- drmModeModeInfoPtr mode;
+ drmModeCrtc *crtc;
+ drmModeConnector *connector;
+ drmModeModeInfo *mode;
} drm_fb_t;
typedef struct drm_fb_page_t drm_fb_page_t;
@@ -31,28 +34,362 @@ struct drm_fb_page_t {
uint32_t drm_fb_id;
};
+typedef struct drm_fb_setup_t {
+ const char *dev;
+ const char *connector;
+ const char *mode;
+} drm_fb_setup_t;
+
+
+static const char * connector_type_name(uint32_t type) {
+ static const char *connector_types[] = {
+ "Unknown",
+ "VGA",
+ "DVII",
+ "DVID",
+ "DVIA",
+ "Composite",
+ "SVIDEO",
+ "LVDS",
+ "Component",
+ "SPinDIN",
+ "DisplayPort",
+ "HDMIA",
+ "HDMIB",
+ "TV",
+ "eDP",
+ "VIRTUAL",
+ "DSI"
+ };
+
+ assert(type < nelems(connector_types));
+
+ return connector_types[type];
+}
+
+
+static setting_desc_t * dev_desc_generator(void *setup_context)
+{
+ return setting_desc_new("DRM Device Path",
+ "dev",
+ "/dev/dri/card[0-9]",
+ "/dev/dri/card0",
+ NULL,
+ NULL);
+}
+
+
+/* returns a NULL-terminated array of drm connectors */
+static const char ** get_connectors(const char *dev)
+{
+ int counts[64] = {}; /* assuming this is big enough */
+ char **connectors;
+ int i, fd;
+ drmModeRes *res;
+
+ assert(dev);
+
+ fd = open(dev, O_RDWR);
+ if (fd == -1)
+ return NULL;
+
+ res = drmModeGetResources(fd);
+ if (!res) {
+ close(fd);
+
+ return NULL;
+ }
+
+ connectors = calloc(res->count_connectors + 1, sizeof(*connectors));
+ if (!connectors) {
+ close(fd);
+
+ return NULL;
+ }
+
+ for (i = 0; i < res->count_connectors; i++) {
+ drmModeConnector *con;
+
+ con = drmModeGetConnector(fd, res->connectors[i]);
+ if (!con) {
+ close(fd);
+
+ return NULL;
+ }
+
+ counts[con->connector_type]++;
+ asprintf(&connectors[i], "%s-%i", connector_type_name(con->connector_type), counts[con->connector_type]); /* TODO: errors */
+
+ drmModeFreeConnector(con);
+ }
+
+ drmModeFreeResources(res);
+ close(fd);
+
+ return (const char **)connectors;
+}
+
+
+static void free_strv(const char **strv)
+{
+ int i;
+
+ for (i = 0; strv[i]; i++)
+ free((void *)strv[i]);
+
+ free((void *)strv);
+}
+
+
+static setting_desc_t * connector_desc_generator(void *setup_context)
+{
+ drm_fb_setup_t *s = setup_context;
+ const char **connectors;
+ setting_desc_t *desc;
+
+ connectors = get_connectors(s->dev);
+ if (!connectors)
+ return NULL;
+
+ desc = setting_desc_new("DRM Connector",
+ "connector",
+ "[a-zA-Z0-9]+",
+ connectors[0],
+ connectors,
+ NULL);
+
+ free_strv(connectors);
+
+ return desc;
+}
+
+
+static drmModeConnector * lookup_connector(int fd, const char *connector)
+{
+ int i, counts[64] = {}; /* assuming this is big enough */
+ drmModeConnector *con = NULL;
+ drmModeRes *res;
+
+ res = drmModeGetResources(fd);
+ if (!res)
+ goto _out;
+
+ for (i = 0; i < res->count_connectors; i++) {
+ char *str;
+
+ con = drmModeGetConnector(fd, res->connectors[i]);
+ if (!con)
+ goto _out_res;
+
+ counts[con->connector_type]++;
+ asprintf(&str, "%s-%i", connector_type_name(con->connector_type), counts[con->connector_type]); /* TODO: errors */
-drm_fb_t * drm_fb_new(int drm_fd, uint32_t crtc_id, uint32_t *connectors, int n_connectors, drmModeModeInfoPtr mode)
+ if (!strcasecmp(str, connector)) {
+ free(str);
+
+ break;
+ }
+
+ free(str);
+ drmModeFreeConnector(con);
+ con = NULL;
+ }
+
+_out_res:
+ drmModeFreeResources(res);
+_out:
+ return con;
+}
+
+
+/* returns a NULL-terminated array of drm modes for the supplied device and connector */
+static const char ** get_modes(const char *dev, const char *connector)
+{
+ char **modes = NULL;
+ int i, fd;
+ drmModeConnector *con;
+
+ assert(dev);
+ assert(connector);
+
+ fd = open(dev, O_RDWR);
+ if (fd == -1)
+ goto _out;
+
+ con = lookup_connector(fd, connector);
+ if (!con)
+ goto _out_fd;
+
+ modes = calloc(con->count_modes + 1, sizeof(*modes));
+ if (!modes)
+ goto _out_con;
+
+ for (i = 0; i < con->count_modes; i++)
+ asprintf(&modes[i], "%s@%"PRIu32, con->modes[i].name, con->modes[i].vrefresh);
+
+_out_con:
+ drmModeFreeConnector(con);
+_out_fd:
+ close(fd);
+_out:
+ return (const char **)modes;
+}
+
+
+static setting_desc_t * mode_desc_generator(void *setup_context)
+{
+ drm_fb_setup_t *s = setup_context;
+ setting_desc_t *desc;
+ const char **modes;
+
+ modes = get_modes(s->dev, s->connector);
+ if (!modes)
+ return NULL;
+
+ desc = setting_desc_new("DRM Video Mode",
+ "mode",
+ "[0-9]+[xX][0-9]+@[0-9]+",
+ modes[0],
+ modes,
+ NULL);
+
+ free_strv(modes);
+
+ return 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 */
+int drm_fb_setup(settings_t *settings, setting_desc_t **next_setting)
+{
+ drm_fb_setup_t context = {};
+ setting_desc_generator_t generators[] = {
+ {
+ .key = "dev",
+ .value_ptr = &context.dev,
+ .func = dev_desc_generator
+ }, {
+ .key = "connector",
+ .value_ptr = &context.connector,
+ .func = connector_desc_generator
+ }, {
+ .key = "mode",
+ .value_ptr = &context.mode,
+ .func = mode_desc_generator
+ },
+ };
+
+ if (!drmAvailable())
+ return -ENOSYS;
+
+ return settings_apply_desc_generators(settings, generators, nelems(generators), &context, next_setting);
+}
+
+
+/* lookup a mode string in the given connector returning its respective modeinfo */
+static drmModeModeInfo * lookup_mode(drmModeConnector *connector, const char *mode)
+{
+ int i;
+
+ assert(connector);
+ assert(mode);
+
+ for (i = 0; i < connector->count_modes; i++) {
+ char *str;
+
+ asprintf(&str, "%s@%"PRIu32, connector->modes[i].name, connector->modes[i].vrefresh);
+ if (!strcasecmp(str, mode)) {
+ free(str);
+
+ return &connector->modes[i];
+ }
+
+ free(str);
+ }
+
+ return NULL;
+}
+
+
+/* prepare the drm context for use with the supplied settings */
+void * drm_fb_init(settings_t *settings)
{
drm_fb_t *c;
+ const char *dev;
+ const char *connector;
+ const char *mode;
+ drmModeEncoder *enc;
+
+ assert(settings);
+
+ if (!drmAvailable())
+ goto _err;
+
+ dev = settings_get_value(settings, "dev");
+ if (!dev)
+ goto _err;
+
+ connector = settings_get_value(settings, "connector");
+ if (!connector)
+ goto _err;
+
+ mode = settings_get_value(settings, "mode");
+ if (!mode)
+ goto _err;
c = calloc(1, sizeof(drm_fb_t));
if (!c)
- return NULL;
+ goto _err;
+
+ c->drm_fd = open(dev, O_RDWR);
+ if (c->drm_fd < 0)
+ goto _err_ctxt;
+
+ c->connector = lookup_connector(c->drm_fd, connector);
+ if (!c->connector)
+ goto _err_fd;
+
+ c->mode = lookup_mode(c->connector, mode);
+ if (!c->mode)
+ goto _err_con;
- c->drm_fd = drm_fd;
- c->crtc_id = crtc_id;
- c->connectors = connectors;
- c->n_connectors = n_connectors;
- c->mode = mode;
+ enc = drmModeGetEncoder(c->drm_fd, c->connector->encoder_id);
+ if (!enc)
+ goto _err_con;
+
+ c->crtc = drmModeGetCrtc(c->drm_fd, enc->crtc_id);
+ if (!c->crtc)
+ goto _err_enc;
+
+ drmModeFreeEncoder(enc);
return c;
+
+_err_enc:
+ drmModeFreeEncoder(enc);
+_err_con:
+ drmModeFreeConnector(c->connector);
+_err_fd:
+ close(c->drm_fd);
+_err_ctxt:
+ free(c);
+_err:
+ return NULL;
}
-void drm_fb_free(drm_fb_t *context)
+void drm_fb_shutdown(void *context)
{
- free(context);
+ drm_fb_t *c = context;
+
+ assert(c);
+
+ close(c->drm_fd);
+ drmModeFreeConnector(c->connector);
+ drmModeFreeCrtc(c->crtc);
+ free(c);
}
@@ -61,7 +398,7 @@ static int drm_fb_acquire(void *context, void *page)
drm_fb_t *c = context;
drm_fb_page_t *p = page;
- return drmModeSetCrtc(c->drm_fd, c->crtc_id, p->drm_fb_id, 0, 0, c->connectors, c->n_connectors, c->mode);
+ return drmModeSetCrtc(c->drm_fd, c->crtc->crtc_id, p->drm_fb_id, 0, 0, &c->connector->connector_id, 1, c->mode);
}
@@ -141,7 +478,7 @@ static int drm_fb_page_flip(void *context, void *page)
drm_fb_t *c = context;
drm_fb_page_t *p = page;
- if (drmModePageFlip(c->drm_fd, c->crtc_id, p->drm_fb_id, DRM_MODE_PAGE_FLIP_EVENT, NULL) < 0)
+ if (drmModePageFlip(c->drm_fd, c->crtc->crtc_id, p->drm_fb_id, DRM_MODE_PAGE_FLIP_EVENT, NULL) < 0)
return -1;
return drmHandleEvent(c->drm_fd, &drm_ev_ctx);
@@ -149,6 +486,9 @@ static int drm_fb_page_flip(void *context, void *page)
fb_ops_t drm_fb_ops = {
+ .setup = drm_fb_setup,
+ .init = drm_fb_init,
+ .shutdown = drm_fb_shutdown,
.acquire = drm_fb_acquire,
.release = drm_fb_release,
.page_alloc = drm_fb_page_alloc,
diff --git a/src/drmsetup.c b/src/drmsetup.c
deleted file mode 100644
index 3670974..0000000
--- a/src/drmsetup.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Rudimentary drm setup dialog... this is currently a very basic stdio thingy.
- */
-
-#include <assert.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-
-#include "util.h"
-
-static const char * encoder_type_name(uint32_t type) {
- static const char *encoder_types[] = {
- "None",
- "DAC",
- "TMDS",
- "LVDAC",
- "VIRTUAL",
- "DSI"
- };
-
- assert(type < nelems(encoder_types));
-
- return encoder_types[type];
-}
-
-
-static const char * connector_type_name(uint32_t type) {
- static const char *connector_types[] = {
- "Unknown",
- "VGA",
- "DVII",
- "DVID",
- "DVIA",
- "Composite",
- "SVIDEO",
- "LVDS",
- "Component",
- "SPinDIN",
- "DisplayPort",
- "HDMIA",
- "HDMIB",
- "TV",
- "eDP",
- "VIRTUAL",
- "DSI"
- };
-
- assert(type < nelems(connector_types));
-
- return connector_types[type];
-}
-
-
-static const char * connection_type_name(int type) {
- static const char *connection_types[] = {
- [1] = "Connected",
- "Disconnected",
- "Unknown"
- };
-
- assert(type < nelems(connection_types));
-
- return connection_types[type];
-}
-
-
-/* interactively setup the drm device, store the selections */
-void drm_setup(int *res_drm_fd, uint32_t *res_crtc_id, uint32_t *res_connector_id, drmModeModeInfoPtr *res_mode)
-{
- int drm_fd, i, connected;
- drmVersionPtr drm_ver;
- drmModeResPtr drm_res;
- drmModeConnectorPtr drm_con;
- drmModeEncoderPtr drm_enc;
- drmModeCrtcPtr drm_crtc;
- char dev[256];
- int connector_num, mode_num;
-
- pexit_if(!drmAvailable(),
- "drm unavailable");
-
- ask_string(dev, sizeof(dev), "DRM device", "/dev/dri/card0");
-
- pexit_if((drm_fd = open(dev, O_RDWR)) < 0,
- "unable to open drm device \"%s\"", dev);
-
- pexit_if(!(drm_ver = drmGetVersion(drm_fd)),
- "unable to get drm version");
-
- printf("\nVersion: %i.%i.%i\nName: \"%.*s\"\nDate: \"%.*s\"\nDescription: \"%.*s\"\n\n",
- drm_ver->version_major,
- drm_ver->version_minor,
- drm_ver->version_patchlevel,
- drm_ver->name_len,
- drm_ver->name,
- drm_ver->date_len,
- drm_ver->date,
- drm_ver->desc_len,
- drm_ver->desc);
-
- pexit_if(!(drm_res = drmModeGetResources(drm_fd)),
- "unable to get drm resources");
-
- printf("\nConnectors\n");
- connected = 0;
- for (i = 0; i < drm_res->count_connectors; i++) {
-
- pexit_if(!(drm_con = drmModeGetConnector(drm_fd, drm_res->connectors[i])),
- "unable to get connector %x", (int)drm_res->connectors[i]);
-
- if (!drm_con->encoder_id) {
- continue;
- }
-
- pexit_if(!(drm_enc = drmModeGetEncoder(drm_fd, drm_con->encoder_id)),
- "unable to get encoder %x", (int)drm_con->encoder_id);
-
- connected++;
-
- printf(" %i: %s (%s%s%s)\n",
- i, connector_type_name(drm_con->connector_type),
- connection_type_name(drm_con->connection),
- drm_con->encoder_id ? " via " : "",
- drm_con->encoder_id ? encoder_type_name(drm_enc->encoder_type) : "");
- /* TODO show mmWidth/mmHeight? */
- }
-
- exit_if(!connected,
- "No connectors available, try different card or my bug?");
- ask_num(&connector_num, drm_res->count_connectors, "Select connector", 0); // TODO default?
-
- pexit_if(!(drm_con = drmModeGetConnector(drm_fd, drm_res->connectors[connector_num])),
- "unable to get connector %x", (int)drm_res->connectors[connector_num]);
- pexit_if(!(drm_enc = drmModeGetEncoder(drm_fd, drm_con->encoder_id)),
- "unable to get encoder %x", (int)drm_con->encoder_id);
-
- pexit_if(!(drm_crtc = drmModeGetCrtc(drm_fd, drm_enc->crtc_id)),
- "unable to get crtc %x", (int)drm_enc->crtc_id);
-
- *res_drm_fd = drm_fd;
- *res_crtc_id = drm_crtc->crtc_id;
- *res_connector_id = drm_con->connector_id;
-
- printf("\nModes\n");
- for (i = 0; i < drm_con->count_modes; i++) {
- printf(" %i: %s @ %"PRIu32"Hz\n",
- i, drm_con->modes[i].name,
- drm_con->modes[i].vrefresh);
- }
- ask_num(&mode_num, drm_con->count_modes, "Select mode", 0); // TODO default to &drm_crtc->mode?
-
- *res_mode = &drm_con->modes[mode_num];
-}
diff --git a/src/drmsetup.h b/src/drmsetup.h
deleted file mode 100644
index 61af2d5..0000000
--- a/src/drmsetup.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _DRM_SETUP_H
-#define _DRM_SETUP_H
-
-#include <stddef.h> /* xf86drmMode.h uses size_t without including stddef.h, sigh */
-#include <stdint.h>
-#include <xf86drmMode.h>
-
-void drm_setup(int *res_drm_fd, uint32_t *res_crtc_id, uint32_t *res_connector_id, drmModeModeInfoPtr *res_mode);
-
-#endif
diff --git a/src/fb.c b/src/fb.c
index a23bce5..f398d43 100644
--- a/src/fb.c
+++ b/src/fb.c
@@ -5,6 +5,7 @@
#include <stdint.h>
#include "fb.h"
+#include "settings.h"
#include "util.h"
/* Copyright (C) 2016-2017 Vito Caputo <vcaputo@pengaru.com> */
@@ -240,6 +241,9 @@ void fb_free(fb_t *fb)
/* TODO: free all the pages */
+ if (fb->ops->shutdown && fb->ops_context)
+ fb->ops->shutdown(fb->ops_context);
+
pthread_mutex_destroy(&fb->ready_mutex);
pthread_cond_destroy(&fb->ready_cond);
pthread_mutex_destroy(&fb->inactive_mutex);
@@ -250,7 +254,7 @@ void fb_free(fb_t *fb)
/* create a new fb instance */
-fb_t * fb_new(const fb_ops_t *ops, void *context, int n_pages)
+fb_t * fb_new(const fb_ops_t *ops, settings_t *settings, int n_pages)
{
_fb_page_t *page;
fb_t *fb;
@@ -271,7 +275,11 @@ fb_t * fb_new(const fb_ops_t *ops, void *context, int n_pages)
return NULL;
fb->ops = ops;
- fb->ops_context = context;
+ if (ops->init) {
+ fb->ops_context = ops->init(settings);
+ if (!fb->ops_context)
+ goto fail;
+ }
for (i = 0; i < n_pages; i++)
fb_page_new(fb);
diff --git a/src/fb.h b/src/fb.h
index 4ca5a49..3f313b2 100644
--- a/src/fb.h
+++ b/src/fb.h
@@ -4,6 +4,8 @@
#include <stdint.h>
#include <string.h>
+#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.
@@ -28,6 +30,9 @@ typedef struct fb_page_t {
/* Supply this struct to fb_new() with the appropriate context */
typedef struct fb_ops_t {
+ int (*setup)(settings_t *settings, setting_desc_t **next);
+ void * (*init)(settings_t *settings);
+ void (*shutdown)(void *context);
int (*acquire)(void *context, void *page);
void (*release)(void *context);
void * (*page_alloc)(void *context, fb_page_t *res_page);
@@ -41,7 +46,7 @@ fb_page_t * fb_page_get(fb_t *fb);
void fb_page_put(fb_t *fb, fb_page_t *page);
void fb_free(fb_t *fb);
void fb_get_put_pages_count(fb_t *fb, unsigned *count);
-fb_t * fb_new(const fb_ops_t *ops, void *context, int n_pages);
+fb_t * fb_new(const fb_ops_t *ops, settings_t *settings, int n_pages);
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);
diff --git a/src/rototiller.c b/src/rototiller.c
index 9362d19..e9bccfa 100644
--- a/src/rototiller.c
+++ b/src/rototiller.c
@@ -11,7 +11,8 @@
#include <xf86drmMode.h>
#include "drm_fb.h"
-#include "drmsetup.h"
+#include "settings.h"
+#include "setup.h"
#include "fb.h"
#include "fps.h"
#include "rototiller.h"
@@ -26,6 +27,8 @@
* 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 "roto32"
+#define DEFAULT_VIDEO "drm"
extern fb_ops_t drm_fb_ops;
@@ -48,16 +51,18 @@ static rototiller_module_t *modules[] = {
};
-static void module_select(int *module)
+rototiller_module_t * module_lookup(const char *name)
{
- int i;
+ unsigned i;
+
+ assert(name);
- printf("\nModules\n");
for (i = 0; i < nelems(modules); i++) {
- printf(" %i: %s - %s\n", i, modules[i]->name, modules[i]->description);
+ if (!strcasecmp(name, modules[i]->name))
+ return modules[i];
}
- ask_num(module, nelems(modules) - 1, "Select module", 0);
+ return NULL;
}
@@ -125,33 +130,229 @@ int parse_argv(int argc, const char *argv[], argv_t *res_args)
return 0;
}
+typedef struct setup_t {
+ settings_t *module;
+ settings_t *video;
+} setup_t;
+
+/* FIXME: this is unnecessarily copy-pasta, i think modules should just be made
+ * more generic to encompass the setting up uniformly, then basically
+ * subclass the video backend vs. renderer stuff.
+ */
+
+/* select video backend if not yet selected, then setup the selected backend. */
+static int setup_video(settings_t *settings, setting_desc_t **next_setting)
+{
+ const char *video;
+
+ /* XXX: there's only one option currently, so this is simple */
+ video = settings_get_key(settings, 0);
+ if (!video) {
+ setting_desc_t *desc;
+ const char *values[] = {
+ "drm",
+ NULL,
+ };
+
+ desc = setting_desc_new("Video Backend",
+ NULL,
+ "drm",
+ DEFAULT_VIDEO,
+ values,
+ NULL);
+ if (!desc)
+ return -ENOMEM;
+
+ *next_setting = desc;
+
+ return 1;
+ }
+
+ /* XXX: this is temporarily simply restricted to drm */
+ if (strcmp(video, "drm"))
+ return -EINVAL;
+
+ return drm_fb_ops.setup(settings, next_setting);
+}
+
+/* select module if not yet selected, then setup the module. */
+static int setup_module(settings_t *settings, setting_desc_t **next_setting)
+{
+ 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;
+
+ for (i = 0; i < nelems(modules); i++) {
+ values[i] = modules[i]->name;
+ annotations[i] = modules[i]->description;
+ }
+
+ desc = setting_desc_new("Renderer Module",
+ NULL,
+ "[a-zA-Z0-9]+",
+ DEFAULT_MODULE,
+ values,
+ annotations);
+ if (!desc)
+ return -ENOMEM;
+
+ *next_setting = desc;
+
+ return 1;
+ }
+
+ module = module_lookup(name);
+ if (!module)
+ return -EINVAL;
+
+ /* TODO: here's where the module-specific settings would get hooked */
+
+ 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, int defaults, 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, 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, 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"
+ );
+}
+
+
+/* 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[])
{
- int drm_fd;
- drmModeModeInfoPtr drm_mode;
- uint32_t drm_crtc_id;
- uint32_t drm_connector_id;
+ argv_t args = {};
+ setup_t setup = {};
+ void *context = NULL;
+ rototiller_module_t *module;
threads_t *threads;
- int module;
fb_t *fb;
- void *context = NULL;
- drm_fb_t *drm_fb;
+ 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, args.defaults, &setup)) < 0,
+ "unable to setup");
- drm_setup(&drm_fd, &drm_crtc_id, &drm_connector_id, &drm_mode);
- module_select(&module);
+ exit_if(r && print_setup_as_args(&setup) < 0,
+ "unable to print setup");
- pexit_if(!(drm_fb = drm_fb_new(drm_fd, drm_crtc_id, &drm_connector_id, 1, drm_mode)),
- "unable to create drm fb backend");
+ exit_if(!(module = module_lookup(settings_get_key(setup.module, 0))),
+ "unable to lookup module from settings \"%s\"", settings_get_key(setup.module, 0));
- pexit_if(!(fb = fb_new(&drm_fb_ops, drm_fb, NUM_FB_PAGES)),
- "unable to create fb frontend");
+ exit_if(!(fb = fb_new(&drm_fb_ops, setup.video, NUM_FB_PAGES)),
+ "unable to create fb");
- pexit_if(!fps_setup(),
+ exit_if(!fps_setup(),
"unable to setup fps counter");
- exit_if(modules[module]->create_context &&
- !(context = modules[module]->create_context()),
+ exit_if(module->create_context &&
+ !(context = module->create_context()),
"unable to create module context");
pexit_if(!(threads = threads_create()),
@@ -163,17 +364,16 @@ int main(int argc, const char *argv[])
fps_print(fb);
page = fb_page_get(fb);
- module_render_page(modules[module], context, threads, page);
+ module_render_page(module, context, threads, page);
fb_page_put(fb, page);
}
threads_destroy(threads);
if (context)
- modules[module]->destroy_context(context);
+ module->destroy_context(context);
fb_free(fb);
- close(drm_fd);
return EXIT_SUCCESS;
}
© All Rights Reserved