From 2806d5f7e1b5223d5b8524ae4770235fc69aa85b Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Thu, 4 Aug 2016 17:43:24 +0200 Subject: Work on cg-base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/cg-base.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ src/cg-base.h | 80 +++++++++++++++++ 2 files changed, 327 insertions(+), 28 deletions(-) diff --git a/src/cg-base.c b/src/cg-base.c index 59248c3..6f6f7df 100644 --- a/src/cg-base.c +++ b/src/cg-base.c @@ -46,6 +46,11 @@ libcoopgamma_context_t cg; */ char** crtcs = NULL; +/** + * Gamma ramp updates for each CRTC + */ +filter_update_t* crtc_updates = NULL; + /** * CRTC and monitor information about * each selected CRTC and connect monitor @@ -58,6 +63,133 @@ libcoopgamma_crtc_info_t* crtc_info = NULL; size_t crtcs_n = 0; +/** + * Contexts for asynchronous ramp updates + */ +static libcoopgamma_async_context_t* asyncs = NULL; + +/** + * The number of pending sends + */ +static size_t pending_sends = 0; + +/** + * The number of pending receives + */ +static size_t pending_recvs = 0; + + + +/** + * Data used to sort CRTC:s + */ +struct crtc_sort_data +{ + /** + * The gamma ramp type + */ + libcoopgamma_depth_t depth; + + /** + * Should be 0 + */ + int __padding; + + /** + * The size of the red gamma ramp + */ + size_t red_size; + + /** + * The size of the green gamma ramp + */ + size_t green_size; + + /** + * The size of the blue gamma ramp + */ + size_t blue_size; + + /** + * The index of the CRTC + */ + size_t index; +}; + + + +/** + * Compare two instances of `crtc_sort_data` + * + * @param a_ Return -1 if this one is lower + * @param b_ Return +1 if this one is higher + * @return See `a_` and `b_`, only -1 or +1 can be returned + */ +static int crtc_sort_data_cmp(const void* a_, const void* b_) +{ + const struct crtc_sort_data* a = a_; + const struct crtc_sort_data* b = b_; + int cmp = memcmp(a, b, sizeof(*a) - sizeof(a->index)); + return cmp ? cmp : a->index < b->index ? -1 : +1; +} + + +/** + * Make elements in `crtc_updates` slaves where appropriate + * + * @return Zero on success, -1 on error + */ +int make_slaves(void) +{ + struct crtc_sort_data* data; + size_t i, j, master = 0, master_i; + + data = alloca(crtcs_n * sizeof(*data)); + memset(data, 0, crtcs_n * sizeof(*data)); + for (i = 0; i < crtcs_n; i++) + { + data[i].depth = crtc_updates[i].filter.depth; + data[i].red_size = crtc_updates[i].filter.ramps.u8.red_size; + data[i].green_size = crtc_updates[i].filter.ramps.u8.green_size; + data[i].blue_size = crtc_updates[i].filter.ramps.u8.blue_size; + data[i].index = i; + } + + qsort(data, crtcs_n, sizeof(*data), crtc_sort_data_cmp); + + for (i = 1; i < crtcs_n; i++) + if (memcmp(data + i, data + master, sizeof(*data) - sizeof(data->index))) + { + if (master + 1 < i) + { + crtc_updates[master_i].slaves = calloc(i - master, sizeof(size_t)); + if (crtc_updates[master_i].slaves == NULL) + return -1; + for (j = 0; master + j < i; j++) + crtc_updates[master_i].slaves[j] = data[master + j].index; + } + master = i; + master_i = data[master].index; + } + else + { + libcoopgamma_ramps_destroy(&(crtc_updates[data[i].index].filter.ramps.u8)); + crtc_updates[data[i].index].master = 0; + crtc_updates[data[i].index].filter.ramps.u8 = crtc_updates[master_i].filter.ramps.u8; + } + + if (master + 1 < i) + { + crtc_updates[master_i].slaves = calloc(i - master, sizeof(size_t)); + if (crtc_updates[master_i].slaves == NULL) + return -1; + for (j = 0; master + j < i; j++) + crtc_updates[master_i].slaves[j] = data[master + j].index; + } + + return 0; +} + /** * Initialise the process, specifically @@ -144,16 +276,11 @@ static int list_crtcs(void) static int get_crtc_info(void) { size_t i, unsynced = 0, selected; - libcoopgamma_async_context_t* async; char* synced; int saved_errno, need_flush = 0, fail_rc = -1; struct pollfd pollfd; - async = alloca(crtcs_n * sizeof(*async)); synced = alloca(crtcs_n * sizeof(*synced)); - for (i = 0; i < crtcs_n; i++) - if (libcoopgamma_async_context_initialise(async + i) < 0) - return -1; memset(synced, 0, crtcs_n * sizeof(*synced)); i = 0; @@ -177,7 +304,7 @@ static int get_crtc_info(void) goto send_fail; need_flush = 0; for (; i < crtcs_n; i++) - if (unsynced++, libcoopgamma_get_gamma_info_send(crtcs[i], &cg, async + i) < 0) + if (unsynced++, libcoopgamma_get_gamma_info_send(crtcs[i], &cg, asyncs + i) < 0) goto send_fail; goto send_done; send_fail: @@ -202,14 +329,14 @@ static int get_crtc_info(void) if (pollfd.revents & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) while (unsynced > 0) - switch (libcoopgamma_synchronise(&cg, async, i, &selected)) + switch (libcoopgamma_synchronise(&cg, asyncs, i, &selected)) { case 0: if (synced[selected]) break; synced[selected] = 1; unsynced -= 1; - if (libcoopgamma_get_gamma_info_recv(crtc_info + selected, &cg, async + selected) < 0) + if (libcoopgamma_get_gamma_info_recv(crtc_info + selected, &cg, asyncs + selected) < 0) goto cg_fail; break; case -1: @@ -230,16 +357,10 @@ static int get_crtc_info(void) } } - for (i = 0; i < crtcs_n; i++) - libcoopgamma_async_context_destroy(async + i); return 0; cg_fail: fail_rc = -2; fail: - saved_errno = errno; - for (i = 0; i < crtcs_n; i++) - libcoopgamma_async_context_destroy(async + i); - errno = saved_errno; return fail_rc; } @@ -259,19 +380,26 @@ static int get_crtc_info(void) * This option can be used multiple times. If it * is not used at all, all CRTC:s will be selected. * + * -p PRIORITY + * Select the priority for the filter, this should + * be a signed two's-complement integer. If + * PRIORITY is "?", the default priority for the + * program is printed to stdout. + * * @param argc The number of command line arguments * @param argv The command line arguments * @return 0 on success, 1 on error */ int main(int argc, char* argv[]) { - int init_failed = 0; int stage = 0; int dealloc_crtcs = 0; int rc = 0; char* method = NULL; char* site = NULL; size_t crtcs_i = 0; + int64_t priority = default_priority; + char* prio = NULL; argv0 = *argv++, argc--; @@ -303,12 +431,12 @@ int main(int argc, char* argv[]) arg = argv[1]; if (!strcmp(opt, "-m")) { - if ((method = arg) == NULL) + if ((method != NULL) || ((method = arg) == NULL)) usage(); } else if (!strcmp(opt, "-s")) { - if ((site = arg) == NULL) + if ((site != NULL) || ((site = arg) == NULL)) usage(); } else if (!strcmp(opt, "-c")) @@ -317,6 +445,11 @@ int main(int argc, char* argv[]) usage(); crtcs[crtcs_i++] = arg; } + else if (!strcmp(opt, "-p")) + { + if ((prio != NULL) || ((prio = arg) == NULL)) + usage(); + } else switch (handle_opt(opt, arg)) { @@ -339,6 +472,14 @@ int main(int argc, char* argv[]) if (handle_args(argc, argv, method, site, crtcs) < 0) goto fail; + if ((prio != NULL) && !strcmp(prio, "?")) + { + printf("%" PRIi64 "\n", priority); + return 0; + } + else if (prio != NULL) + priority = (int64_t)atoll(prio); + if ((method != NULL) && !strcmp(method, "?")) { if (list_methods() < 0) @@ -351,8 +492,8 @@ int main(int argc, char* argv[]) stage++; if (libcoopgamma_connect(method, site, &cg) < 0) { - init_failed = (errno == 0); - goto fail; + fprintf(stderr, "%s: server failed to initialise\n", argv0); + goto custom_fail; } stage++; @@ -377,9 +518,14 @@ int main(int argc, char* argv[]) for (; crtcs[crtcs_n] != NULL; crtcs_n++); } - crtc_info = calloc(crtcs_n + 1, sizeof(*crtc_info)); - if (crtc_info == NULL) - goto fail; + if (crtcs_n == 0) + { + fprintf(stderr, "%s: no CRTC:s are available\n", argv0); + goto custom_fail; + } + + crtc_info = alloca(crtcs_n * sizeof(*crtc_info)); + memset(crtc_info, 0, crtcs_n * sizeof(*crtc_info)); for (crtcs_i = 0; crtcs_i < crtcs_n; crtcs_i++) if (libcoopgamma_crtc_info_initialise(crtc_info + crtcs_i) < 0) goto cg_fail; @@ -387,6 +533,56 @@ int main(int argc, char* argv[]) if (libcoopgamma_set_nonblocking(&cg, 1) < 0) goto fail; + asyncs = alloca(crtcs_n * sizeof(*asyncs)); + memset(asyncs, 0, crtcs_n * sizeof(*asyncs)); + for (crtcs_i = 0; crtcs_i < crtcs_n; crtcs_i++) + if (libcoopgamma_async_context_initialise(asyncs + crtcs_i) < 0) + goto fail; + + crtc_updates = alloca(crtcs_n * sizeof(*crtc_updates)); + memset(crtc_updates, 0, crtcs_n * sizeof(*crtc_updates)); + for (crtcs_i = 0; crtcs_i < crtcs_n; crtcs_i++) + { + if (libcoopgamma_filter_initialise(&(crtc_updates[crtcs_i].filter)) < 0) + goto fail; + if (libcoopgamma_error_initialise(&(crtc_updates[crtcs_i].error)) < 0) + goto fail; + crtc_updates[crtcs_i].synced = 1; + crtc_updates[crtcs_i].failed = 0; + crtc_updates[crtcs_i].master = 1; + crtc_updates[crtcs_i].slaves = NULL; + crtc_updates[crtcs_i].filter.crtc = crtcs[crtcs_i]; + crtc_updates[crtcs_i].filter.priority = priority; + crtc_updates[crtcs_i].filter.depth = crtc_info[crtcs_i].depth; + crtc_updates[crtcs_i].filter.ramps.u8.red_size = crtc_info[crtcs_i].red_size; + crtc_updates[crtcs_i].filter.ramps.u8.green_size = crtc_info[crtcs_i].green_size; + crtc_updates[crtcs_i].filter.ramps.u8.blue_size = crtc_info[crtcs_i].blue_size; + switch (crtc_updates[crtcs_i].filter.depth) + { + case LIBCOOPGAMMA_UINT8: + libcoopgamma_ramps_initialise(&(crtc_updates[crtcs_i].filter.ramps.u8)); + break; + case LIBCOOPGAMMA_UINT16: + libcoopgamma_ramps_initialise(&(crtc_updates[crtcs_i].filter.ramps.u16)); + break; + case LIBCOOPGAMMA_UINT32: + libcoopgamma_ramps_initialise(&(crtc_updates[crtcs_i].filter.ramps.u32)); + break; + case LIBCOOPGAMMA_UINT64: + libcoopgamma_ramps_initialise(&(crtc_updates[crtcs_i].filter.ramps.u64)); + break; + case LIBCOOPGAMMA_FLOAT: + libcoopgamma_ramps_initialise(&(crtc_updates[crtcs_i].filter.ramps.f)); + break; + case LIBCOOPGAMMA_DOUBLE: + libcoopgamma_ramps_initialise(&(crtc_updates[crtcs_i].filter.ramps.d)); + break; + default: + fprintf(stderr, "%s: internal error: gamma ramp type is unrecognised\n", argv0); + goto custom_fail; + } + } + switch (get_crtc_info()) { case 0: @@ -397,7 +593,17 @@ int main(int argc, char* argv[]) goto cg_fail; } - /* TODO start */ + switch (start()) + { + case 0: + break; + case -1: + goto fail; + case -2: + goto cg_fail; + case -3: + goto custom_fail; + } done: if (dealloc_crtcs) @@ -405,17 +611,30 @@ int main(int argc, char* argv[]) if (crtc_info != NULL) for (crtcs_i = 0; crtcs_i < crtcs_n; crtcs_i++) libcoopgamma_crtc_info_destroy(crtc_info + crtcs_i); - free(crtc_info); + if (asyncs != NULL) + for (crtcs_i = 0; crtcs_i < crtcs_n; crtcs_i++) + libcoopgamma_async_context_destroy(asyncs + crtcs_i); if (stage >= 1) libcoopgamma_context_destroy(&cg, stage >= 2); + if (crtc_updates != NULL) + for (crtcs_i = 0; crtcs_i < crtcs_n; crtcs_i++) + { + if (crtc_updates[crtcs_i].master == 0) + memset(&(crtc_updates[crtcs_i].filter.ramps.u8), 0, sizeof(crtc_updates[crtcs_i].filter.ramps.u8)); + crtc_updates[crtcs_i].filter.crtc = NULL; + libcoopgamma_filter_destroy(&(crtc_updates[crtcs_i].filter)); + libcoopgamma_error_destroy(&(crtc_updates[crtcs_i].error)); + free(crtc_updates[crtcs_i].slaves); + } return rc; + custom_fail: + rc = 1; + goto done; + fail: rc = 1; - if (init_failed) - fprintf(stderr, "%s: server failed to initialise\n", argv0); - else - perror(argv0); + perror(argv0); goto done; cg_fail: diff --git a/src/cg-base.h b/src/cg-base.h index 662f044..13667b7 100644 --- a/src/cg-base.h +++ b/src/cg-base.h @@ -19,6 +19,55 @@ +/** + * Information (except asynchronous call context) + * required to update the gamma ramps on a CRTC. + */ +typedef struct filter_update +{ + /** + * The filter to update + * + * `.filter.crtc` and `.filter.priority` + * are preconfigured + */ + libcoopgamma_filter_t filter; + + /** + * Has the update been synchronised? + */ + int synced; + + /** + * Did the update fail? + */ + int failed; + + /** + * Error description if `.failed` is true + */ + libcoopgamma_error_t error; + + /** + * If zero, the ramps in `.filter` shall + * neither be modified nor freed. + */ + int master; + + /** + * 0-terminated list of elements in + * `.crtc_updates` which shares gamma + * ramps with this instance + * + * This will only be set if `.master` + * is true. + */ + size_t* slaves; + +} filter_update_t; + + + /** * The process's name */ @@ -34,6 +83,11 @@ extern libcoopgamma_context_t cg; */ extern char** crtcs; +/** + * Gamma ramp updates for each CRTC + */ +extern filter_update_t* crtc_updates; + /** * CRTC and monitor information about * each selected CRTC and connect monitor @@ -47,6 +101,22 @@ extern size_t crtcs_n; +/** + * The default filter priority for the program + */ +extern const int64_t default_priority; + + + +/** + * Make elements in `crtc_updates` slaves where appropriate + * + * @return Zero on success, -1 on error + */ +int make_slaves(void); + + + /** * Print usage information and exit */ @@ -90,3 +160,13 @@ __attribute__((__nonnull__(2))) #endif extern int handle_args(int argc, char* argv[], char* method, char* site, char** crtcs); +/** + * The main function for the program-specific code + * + * @return 0: Success + * -1: Error, `errno` set + * -2: Error, `cg.error` set + * -3: Error, message already printed + */ +extern int start(void); + -- cgit v1.2.3-70-g09d2