/* See LICENSE file for copyright and license details. */
#include "types-output.h"
#include "util.h"
#include <stdlib.h>
#include <string.h>
/**
* Free all resources allocated to an output.
* The allocation of `output` itself is not freed,
* nor is its the libgamma destroyed.
*
* @param this The output
*/
void
output_destroy(struct output *restrict this)
{
size_t i;
if (this->supported != LIBGAMMA_NO) {
switch (this->depth) {
case 8:
libgamma_gamma_ramps8_destroy(&this->saved_ramps.u8);
for (i = 0; i < this->table_size; i++)
libgamma_gamma_ramps8_destroy(&this->table_sums[i].u8);
break;
case 16:
libgamma_gamma_ramps16_destroy(&this->saved_ramps.u16);
for (i = 0; i < this->table_size; i++)
libgamma_gamma_ramps16_destroy(&this->table_sums[i].u16);
break;
case 32:
libgamma_gamma_ramps32_destroy(&this->saved_ramps.u32);
for (i = 0; i < this->table_size; i++)
libgamma_gamma_ramps32_destroy(&this->table_sums[i].u32);
break;
case 64:
libgamma_gamma_ramps64_destroy(&this->saved_ramps.u64);
for (i = 0; i < this->table_size; i++)
libgamma_gamma_ramps64_destroy(&this->table_sums[i].u64);
break;
case -1:
libgamma_gamma_rampsf_destroy(&this->saved_ramps.f);
for (i = 0; i < this->table_size; i++)
libgamma_gamma_rampsf_destroy(&this->table_sums[i].f);
break;
case -2:
libgamma_gamma_rampsd_destroy(&this->saved_ramps.d);
for (i = 0; i < this->table_size; i++)
libgamma_gamma_rampsd_destroy(&this->table_sums[i].d);
break;
default:
break; /* impossible */
}
}
for (i = 0; i < this->table_size; i++)
filter_destroy(&this->table_filters[i]);
free(this->table_filters);
free(this->table_sums);
free(this->name);
}
#if defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-align"
#endif
/**
* Marshal an output
*
* @param this The output
* @param buf Output buffer for the marshalled output,
* `NULL` just measure how large the buffers
* needs to be
* @return The number of marshalled byte
*/
size_t
output_marshal(const struct output *restrict this, void *restrict buf)
{
size_t off = 0, i, n;
char *bs = buf;
if (bs)
*(signed *)&bs[off] = this->depth;
off += sizeof(signed);
if (bs)
*(size_t *)&bs[off] = this->red_size;
off += sizeof(size_t);
if (bs)
*(size_t *)&bs[off] = this->green_size;
off += sizeof(size_t);
if (bs)
*(size_t *)&bs[off] = this->blue_size;
off += sizeof(size_t);
if (bs)
*(size_t *)&bs[off] = this->ramps_size;
off += sizeof(size_t);
if (bs)
*(enum libgamma_decision *)&bs[off] = this->supported;
off += sizeof(enum libgamma_decision);
if (bs)
*(enum colourspace *)&bs[off] = this->colourspace;
off += sizeof(enum colourspace);
if (bs)
*(int *)&bs[off] = this->name_is_edid;
off += sizeof(int);
if (bs)
*(unsigned *)&bs[off] = this->red_x;
off += sizeof(unsigned);
if (bs)
*(unsigned *)&bs[off] = this->red_y;
off += sizeof(unsigned);
if (bs)
*(unsigned *)&bs[off] = this->green_x;
off += sizeof(unsigned);
if (bs)
*(unsigned *)&bs[off] = this->green_y;
off += sizeof(unsigned);
if (bs)
*(unsigned *)&bs[off] = this->blue_x;
off += sizeof(unsigned);
if (bs)
*(unsigned *)&bs[off] = this->blue_y;
off += sizeof(unsigned);
if (bs)
*(unsigned *)&bs[off] = this->white_x;
off += sizeof(unsigned);
if (bs)
*(unsigned *)&bs[off] = this->white_y;
off += sizeof(unsigned);
n = strlen(this->name) + 1;
if (bs)
memcpy(&bs[off], this->name, n);
off += n;
off += gamma_ramps_marshal(&(this->saved_ramps), bs ? &bs[off] : NULL, this->ramps_size);
if (bs)
*(size_t *)&bs[off] = this->table_size;
off += sizeof(size_t);
for (i = 0; i < this->table_size; i++) {
off += filter_marshal(this->table_filters + i, bs ? &bs[off] : NULL, this->ramps_size);
off += gamma_ramps_marshal(this->table_sums + i, bs ? &bs[off] : NULL, this->ramps_size);
}
return off;
}
/**
* Unmarshal an output
*
* @param this Output for the output
* @param buf Buffer with the marshalled output
* @return The number of unmarshalled bytes, 0 on error
*/
size_t
output_unmarshal(struct output *restrict this, const void *restrict buf)
{
size_t off = 0, i, n;
const char *bs = buf;
this->crtc = NULL;
this->name = NULL;
this->depth = *(const signed *)&bs[off];
off += sizeof(signed);
this->red_size = *(const size_t *)&bs[off];
off += sizeof(size_t);
this->green_size = *(const size_t *)&bs[off];
off += sizeof(size_t);
this->blue_size = *(const size_t *)&bs[off];
off += sizeof(size_t);
this->ramps_size = *(const size_t *)&bs[off];
off += sizeof(size_t);
this->supported = *(const enum libgamma_decision *)&bs[off];
off += sizeof(enum libgamma_decision);
this->colourspace = *(const enum colourspace *)&bs[off];
off += sizeof(enum colourspace);
this->name_is_edid = *(const int *)&bs[off];
off += sizeof(int);
this->red_x = *(const unsigned *)&bs[off];
off += sizeof(unsigned);
this->red_y = *(const unsigned *)&bs[off];
off += sizeof(unsigned);
this->green_x = *(const unsigned *)&bs[off];
off += sizeof(unsigned);
this->green_y = *(const unsigned *)&bs[off];
off += sizeof(unsigned);
this->blue_x = *(const unsigned *)&bs[off];
off += sizeof(unsigned);
this->blue_y = *(const unsigned *)&bs[off];
off += sizeof(unsigned);
this->white_x = *(const unsigned *)&bs[off];
off += sizeof(unsigned);
this->white_y = *(const unsigned *)&bs[off];
off += sizeof(unsigned);
n = strlen(&bs[off]) + 1;
this->name = memdup(&bs[off], n);
if (this->name == NULL)
return 0;
off += n;
COPY_RAMP_SIZES(&this->saved_ramps.u8, this);
off += n = gamma_ramps_unmarshal(&this->saved_ramps, &bs[off], this->ramps_size);
if (n == 0)
return 0;
this->table_size = this->table_alloc = *(const size_t*)&bs[off];
off += sizeof(size_t);
if (this->table_size > 0) {
this->table_filters = calloc(this->table_size, sizeof(*this->table_filters));
if (!this->table_filters)
return 0;
this->table_sums = calloc(this->table_size, sizeof(*this->table_sums));
if (!this->table_sums)
return 0;
}
for (i = 0; i < this->table_size; i++) {
off += n = filter_unmarshal(&this->table_filters[i], &bs[off], this->ramps_size);
if (!n)
return 0;
COPY_RAMP_SIZES(&this->table_sums[i].u8, this);
off += n = gamma_ramps_unmarshal(&this->table_sums[i], &bs[off], this->ramps_size);
if (!n)
return 0;
}
return off;
}
#if defined(__clang__)
# pragma GCC diagnostic pop
#endif
/**
* Compare to outputs by the names of their respective CRTC:s
*
* @param a Return -1 if this one is lower
* @param b Return +1 if this one is higher
* @return See description of `a` and `b`,
* 0 if returned if they are the same
*/
int
output_cmp_by_name(const void *restrict a, const void *restrict b)
{
const struct output *x = a, *y = b;
return strcmp(x->name, y->name);
}
/**
* Find an output by its name
*
* @param key The name of the output
* @param base The array of outputs
* @param n The number of elements in `base`
* @return Output find in `base`, `NULL` if not found
*/
struct output *
output_find_by_name(const char *restrict key, struct output *restrict base, size_t n)
{
struct output k;
#if defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-qual"
#endif
k.name = (char *)key;
#if defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
return bsearch(&k, base, n, sizeof(*base), output_cmp_by_name);
}