[PATCH 2/6] Attach input profiles and build corresponding LUTs
Bryce Harrington
bryce at osg.samsung.com
Wed Oct 15 21:54:37 PDT 2014
On Mon, Oct 13, 2014 at 07:40:47PM +0200, Niels Ole Salscheider wrote:
> This implements the functionality to attach a profile to a surface
> in weston. An LUT is built from the profile that can be used to
> transform colors from the input color space to the blending color
> space.
>
> An sRGB color space is assumed for all newly created outputs
>
> This patch uses the sRGB color space as blending space because it
> uses 8 bit LUTs for now and I want to avoid additional banding. In
> the long term we should use a linear blending space though to get
> correct results.
>
> Signed-off-by: Niels Ole Salscheider <niels_ole at salscheider-online.de>
> ---
> Makefile.am | 3 +
> configure.ac | 2 +-
> src/compositor.c | 411 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> src/compositor.h | 41 ++++++
> 4 files changed, 453 insertions(+), 4 deletions(-)
>
> diff --git a/Makefile.am b/Makefile.am
> index 3af3b46..1ecab56 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -45,6 +45,9 @@ weston_CPPFLAGS = $(AM_CPPFLAGS) -DIN_WESTON
> weston_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(LIBUNWIND_CFLAGS)
> weston_LDADD = $(COMPOSITOR_LIBS) $(LIBUNWIND_LIBS) \
> $(DLOPEN_LIBS) -lm libshared.la
> +if HAVE_LCMS
> +weston_LDADD += $(LCMS_LIBS)
> +endif
>
> weston_SOURCES = \
> src/git-version.h \
> diff --git a/configure.ac b/configure.ac
> index 1c133bd..00b7cca 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -59,7 +59,7 @@ AC_CHECK_HEADERS([execinfo.h])
>
> AC_CHECK_FUNCS([mkostemp strchrnul initgroups posix_fallocate])
>
> -COMPOSITOR_MODULES="wayland-server >= 1.5.91 pixman-1 >= 0.25.2"
> +COMPOSITOR_MODULES="wayland-server >= 1.5.91 pixman-1 >= 0.25.2 glib-2.0"
Depending on glib seems a pretty big step. I see it's needed for
GHashTable, anything else?
Wayland has a wl_map data structure; could that be used instead of
GHashTable, in order to avoid the glib dependency?
> AC_ARG_ENABLE(egl, [ --disable-egl],,
> enable_egl=yes)
> diff --git a/src/compositor.c b/src/compositor.c
> index 29731c7..4f959a4 100644
> --- a/src/compositor.c
> +++ b/src/compositor.c
> @@ -56,6 +56,7 @@
> #include "compositor.h"
> #include "scaler-server-protocol.h"
> #include "presentation_timing-server-protocol.h"
> +#include "cms-server-protocol.h"
> #include "../shared/os-compatibility.h"
> #include "git-version.h"
> #include "version.h"
> @@ -518,7 +519,8 @@ surface_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
> }
>
> static void
> -weston_surface_state_init(struct weston_surface_state *state)
> +weston_surface_state_init(struct weston_surface_state *state,
> + struct weston_compositor *compositor)
> {
> state->newly_attached = 0;
> state->buffer = NULL;
> @@ -539,6 +541,8 @@ weston_surface_state_init(struct weston_surface_state *state)
> state->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
> state->buffer_viewport.surface.width = -1;
> state->buffer_viewport.changed = 0;
> +
> + state->colorspace = &compositor->srgb_colorspace;
> }
>
> static void
> @@ -576,6 +580,163 @@ weston_surface_state_set_buffer(struct weston_surface_state *state,
> &state->buffer_destroy_listener);
> }
>
> +#if HAVE_LCMS
> +static void
> +weston_free_clut(struct weston_clut *clut)
> +{
> + clut->points = 0;
> + free(clut->data);
> + clut->data = NULL;
> +}
> +
> +static void
> +weston_build_clut(struct weston_colorspace *colorspace)
> +{
> + cmsHTRANSFORM xform;
> + unsigned r, g, b;
> + cmsHPROFILE input_profile, output_profile;
> + cmsUInt8Number input_id[16];
> + cmsUInt8Number output_id[16];
> + struct weston_clut *clut = &colorspace->clut;
> + struct weston_compositor *ec = colorspace->compositor;
> +
> + weston_free_clut(clut);
> +
> + if (colorspace->input) {
> + input_profile = colorspace->lcms_handle;
> + output_profile = ec->blending_colorspace.lcms_handle;
> + } else {
> + input_profile = ec->blending_colorspace.lcms_handle;
> + output_profile = colorspace->lcms_handle;
> + }
> +
> + cmsGetHeaderProfileID(input_profile, input_id);
> + cmsGetHeaderProfileID(output_profile, output_id);
> + if (memcmp(input_id, output_id, 16) == 0)
> + return;
Don't hide the error here, propagate it by returning false.
And obviously all callers of this routine should check it. :-)
> + clut->points = 64;
Does this ever change to anything besides 64? If not, wouldn't this be
better as a constant?
> + xform = cmsCreateTransform(input_profile, TYPE_RGB_8, output_profile,
> + TYPE_RGB_8, INTENT_PERCEPTUAL, 0);
Looks like cmsCreateTransform has a return value that can be checked for
NULL to detect errors. Looks like it signals some errors that could be
propagated too.
> + clut->data = malloc(clut->points * clut->points * clut->points *
> + 3 * sizeof(char));
Needs error check here too.
> + for (b = 0; b < clut->points; b++)
> + for (g = 0; g < clut->points; g++)
> + for (r = 0; r < clut->points; r++) {
> + char in[3];
> + unsigned entry = 3 * (r + clut->points *
> + (g + clut->points * b));
> + const float step = 255.0 / (clut->points - 1);
> + in[0] = (char) (r * step + 0.5);
> + in[1] = (char) (g * step + 0.5);
> + in[2] = (char) (b * step + 0.5);
> + cmsDoTransform(xform, in,
> + &clut->data[entry], 1);
> + }
> +
> + cmsDeleteTransform(xform);
> +}
> +
> +WL_EXPORT struct weston_colorspace *
> +weston_colorspace_from_fd(int fd, int input, struct weston_compositor *ec)
> +{
> + FILE *profile;
> + cmsHPROFILE lcms_handle;
> + cmsUInt8Number profile_id[17];
> + struct weston_colorspace *colorspace;
> +
> + profile = fdopen(fd, "r");
> + if (!profile) {
> + return 0;
Should return NULL explicitly rather than 0 here.
> + }
> +
> + lcms_handle = cmsOpenProfileFromStream(profile, "r");
> + if (!lcms_handle) {
> + return 0;
> + }
Same here. In fact you may want to do a goto error handler, so you can
close the fd and other cleanup.
> + cmsMD5computeID(lcms_handle);
Check return status for FALSE on this one.
> + cmsGetHeaderProfileID(lcms_handle, profile_id);
> + profile_id[16] = '\0';
Google isn't giving up an API definition on this one so don't know if it
returns an error code.
> + if (input)
> + colorspace = g_hash_table_lookup(ec->input_colorspaces,
> + profile_id);
> + else
> + colorspace = g_hash_table_lookup(ec->output_colorspaces,
> + profile_id);
> + if (colorspace) {
> + colorspace->refcount++;
> +
> + cmsCloseProfile(lcms_handle);
> + return colorspace;
> + }
> +
> + colorspace = calloc(1, sizeof(struct weston_colorspace));
Check for NULL on the calloc
> + colorspace->refcount = 1;
> + colorspace->destroyable = 1;
> + colorspace->input = input;
> + colorspace->lcms_handle = lcms_handle;
> + colorspace->compositor = ec;
> +
> + weston_build_clut(colorspace);
Check error return for weston_build_clut.
> + g_hash_table_insert(ec->input_colorspaces,
> + g_strdup((const gchar *) profile_id),
> + colorspace);
> +
> + return colorspace;
> +}
> +
> +/* This function is called when a color space is removed from the hash table */
> +static void
> +weston_colorspace_free(struct weston_colorspace *colorspace)
> +{
> + if (!colorspace->destroyable)
> + return;
No chance this can't result in memory leakage?
> + cmsCloseProfile(colorspace->lcms_handle);
> +
> + weston_free_clut(&colorspace->clut);
> + free(colorspace);
> +}
> +
> +WL_EXPORT void
> +weston_colorspace_destroy(struct weston_colorspace *colorspace)
> +{
> + cmsUInt8Number profile_id[17];
> +
> + if (!colorspace->destroyable)
> + return;
> +
> + colorspace->refcount--;
> + if (colorspace->refcount > 0)
> + return;
> +
> + cmsGetHeaderProfileID(colorspace->lcms_handle, profile_id);
> + profile_id[16] = '\0';
> +
> + if (colorspace->input)
> + g_hash_table_remove(colorspace->compositor->input_colorspaces,
> + profile_id);
> + else
> + g_hash_table_remove(colorspace->compositor->output_colorspaces,
> + profile_id);
> +
> +}
Why is there both a *_free() and a *_destroy() for weston_colorspace?
> +static void
> +weston_colorspace_resource_destroy(struct wl_resource *cms_colorspace)
> +{
> + struct weston_colorspace *colorspace =
> + wl_resource_get_user_data(cms_colorspace);
> + weston_colorspace_destroy(colorspace);
> +}
> +#endif
> +
> WL_EXPORT struct weston_surface *
> weston_surface_create(struct weston_compositor *compositor)
> {
> @@ -597,7 +758,9 @@ weston_surface_create(struct weston_compositor *compositor)
> surface->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
> surface->buffer_viewport.surface.width = -1;
>
> - weston_surface_state_init(&surface->pending);
> + surface->colorspace = &compositor->srgb_colorspace;
> +
> + weston_surface_state_init(&surface->pending, compositor);
>
> surface->output = NULL;
>
> @@ -615,6 +778,7 @@ weston_surface_create(struct weston_compositor *compositor)
> wl_list_init(&surface->subsurface_list);
> wl_list_init(&surface->subsurface_list_pending);
>
> +
> return surface;
Extraneous newline?
> }
>
> @@ -2369,6 +2533,8 @@ weston_surface_commit_state(struct weston_surface *surface,
> wl_list_insert_list(&surface->feedback_list,
> &state->feedback_list);
> wl_list_init(&state->feedback_list);
> +
> + surface->colorspace = state->colorspace;
> }
>
> static void
> @@ -2609,6 +2775,8 @@ weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
> sub->cached.buffer_viewport.surface =
> surface->pending.buffer_viewport.surface;
>
> + sub->cached.colorspace = surface->colorspace;
> +
> weston_surface_reset_pending_buffer(surface);
>
> pixman_region32_copy(&sub->cached.opaque, &surface->pending.opaque);
> @@ -3041,7 +3209,7 @@ weston_subsurface_create(uint32_t id, struct weston_surface *surface,
> sub, subsurface_resource_destroy);
> weston_subsurface_link_surface(sub, surface);
> weston_subsurface_link_parent(sub, parent);
> - weston_surface_state_init(&sub->cached);
> + weston_surface_state_init(&sub->cached, surface->compositor);
> sub->cached_buffer_ref.buffer = NULL;
> sub->synchronized = 1;
>
> @@ -3363,6 +3531,10 @@ weston_output_destroy(struct weston_output *output)
> wl_signal_emit(&output->compositor->output_destroyed_signal, output);
> wl_signal_emit(&output->destroy_signal, output);
>
> +#ifdef HAVE_LCMS
> + weston_colorspace_destroy(output->colorspace);
> +#endif
> +
> free(output->name);
> pixman_region32_fini(&output->region);
> pixman_region32_fini(&output->previous_damage);
> @@ -3554,6 +3726,7 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
> output->mm_height = mm_height;
> output->dirty = 1;
> output->original_scale = scale;
> + output->colorspace = &c->srgb_colorspace;
>
> weston_output_transform_scale_init(output, transform, scale);
> weston_output_init_zoom(output);
> @@ -3917,6 +4090,181 @@ bind_presentation(struct wl_client *client,
> presentation_send_clock_id(resource, compositor->presentation_clock);
> }
>
> +#ifdef HAVE_LCMS
> +static void
> +cms_colorspace_destroy(struct wl_client *client,
> + struct wl_resource *cms_colorspace)
> +{
> + wl_resource_destroy(cms_colorspace);
> +}
> +
> +static void
> +cms_colorspace_get_profile_fd(struct wl_client *client,
> + struct wl_resource *cms_colorspace)
> +{
> + struct weston_colorspace *colorspace =
> + wl_resource_get_user_data(cms_colorspace);
> + char template[24];
> + FILE *profilefile;
> + int fd = -1;
> +
> + strncpy(template, "/tmp/weston-cms-XXXXXX", 24);
> + fd = mkstemp(template);
> + profilefile = fdopen(fd, "w");
> + cmsSaveProfileToStream(colorspace->lcms_handle, profilefile);
> + rewind(profilefile);
> +
> + wl_cms_colorspace_send_profile_data(cms_colorspace, fd);
> +
> + close(fd);
> +}
> +
> +static const struct wl_cms_colorspace_interface cms_colorspace_interface = {
> + cms_colorspace_destroy,
> + cms_colorspace_get_profile_fd
> +};
> +
> +static void
> +cms_set_colorspace(struct wl_client *client, struct wl_resource *cms,
> + struct wl_resource *surface_resource,
> + struct wl_resource *colorspace_resource)
> +{
> + struct weston_surface *surface =
> + wl_resource_get_user_data(surface_resource);
wl_resource_get_user_data() returns a void*; does this need a cast?
Also, I can't tell whether it's guaranteed not to return NULL or not.
If it can return NULL, better check for it here.
> +
> + struct weston_colorspace *colorspace =
> + wl_resource_get_user_data(colorspace_resource);
> + surface->pending.colorspace = colorspace;
> +}
> +
> +static void
> +cms_colorspace_from_fd(struct wl_client *client, struct wl_resource *cms,
> + int fd, uint32_t id)
> +{
> + struct weston_compositor *compositor =
> + wl_resource_get_user_data(cms);
> +
> + struct weston_colorspace *colorspace;
> + struct wl_resource *colorspace_resource;
> +
> + colorspace = weston_colorspace_from_fd(fd, 1, compositor);
> + if (colorspace == NULL) {
> + wl_resource_post_error(cms,
> + WL_CMS_ERROR_INVALID_PROFILE,
> + "the passed ICC profile is not valid");
> + return;
Should return false in case of an error.
> + }
> +
> + colorspace_resource = wl_resource_create(client,
> + &wl_cms_colorspace_interface,
> + 1, id);
> + if (colorspace_resource == NULL) {
> + weston_colorspace_destroy(colorspace);
> + wl_client_post_no_memory(client);
> + return;
ditto
> + }
> + wl_resource_set_implementation(colorspace_resource,
> + &cms_colorspace_interface, colorspace,
> + weston_colorspace_resource_destroy);
> +}
> +
> +static void
> +cms_output_colorspace(struct wl_client *client, struct wl_resource *cms,
> + struct wl_resource *output_resource, uint32_t id)
> +{
> + struct weston_output *output =
> + wl_resource_get_user_data(output_resource);
> +
> + struct weston_colorspace *colorspace;
> + struct wl_resource *colorspace_resource;
> +
> + colorspace = output->colorspace;
> + colorspace->refcount++;
> +
> + colorspace_resource = wl_resource_create(client,
> + &wl_cms_colorspace_interface,
> + 1, id);
> + if (colorspace_resource == NULL) {
> + weston_colorspace_destroy(colorspace);
> + wl_client_post_no_memory(client);
> + return;
> + }
> + wl_resource_set_implementation(colorspace_resource,
> + &cms_colorspace_interface, colorspace,
> + weston_colorspace_resource_destroy);
> +}
> +
> +static void
> +cms_srgb_colorspace(struct wl_client *client, struct wl_resource *cms,
> + uint32_t id)
> +{
> + struct weston_compositor *compositor =
> + wl_resource_get_user_data(cms);
> + struct weston_colorspace *colorspace;
> + struct wl_resource *colorspace_resource;
> +
> + colorspace = &compositor->srgb_colorspace;
> +
> + colorspace_resource = wl_resource_create(client,
> + &wl_cms_colorspace_interface,
> + 1, id);
> + if (colorspace_resource == NULL) {
> + weston_colorspace_destroy(colorspace);
> + wl_client_post_no_memory(client);
> + return;
> + }
> + wl_resource_set_implementation(colorspace_resource,
> + &cms_colorspace_interface, colorspace,
> + weston_colorspace_resource_destroy);
> +}
> +
> +static void
> +cms_blending_colorspace(struct wl_client *client, struct wl_resource *cms,
> + uint32_t id)
> +{
> + struct weston_compositor *compositor =
> + wl_resource_get_user_data(cms);
> + struct weston_colorspace *colorspace;
> + struct wl_resource *colorspace_resource;
> +
> + colorspace = &compositor->blending_colorspace;
> +
> + colorspace_resource = wl_resource_create(client,
> + &wl_cms_colorspace_interface,
> + 1, id);
> + if (colorspace_resource == NULL) {
> + weston_colorspace_destroy(colorspace);
> + wl_client_post_no_memory(client);
> + return;
> + }
> + wl_resource_set_implementation(colorspace_resource,
> + &cms_colorspace_interface, colorspace,
> + weston_colorspace_resource_destroy);
> +}
> +
> +static const struct wl_cms_interface cms_interface = {
> + cms_set_colorspace,
> + cms_colorspace_from_fd,
> + cms_output_colorspace,
> + cms_srgb_colorspace,
> + cms_blending_colorspace
> +};
> +
> +static void
> +bind_cms(struct wl_client *client, void *data, uint32_t version, uint32_t id)
> +{
> + struct wl_resource *resource;
> +
> + resource = wl_resource_create(client, &wl_cms_interface, 1, id);
> + if (resource == NULL) {
> + wl_client_post_no_memory(client);
> + return;
> + }
> +
> + wl_resource_set_implementation(resource, &cms_interface, data, NULL);
> +}
> +#endif
> +
> static void
> compositor_bind(struct wl_client *client,
> void *data, uint32_t version, uint32_t id)
> @@ -4016,6 +4364,12 @@ weston_compositor_init(struct weston_compositor *ec,
> ec, bind_presentation))
> return -1;
>
> +#ifdef HAVE_LCMS
> + if (!wl_global_create(display, &wl_cms_interface, 1,
> + ec, bind_cms))
> + return -1;
> +#endif
> +
> wl_list_init(&ec->view_list);
> wl_list_init(&ec->plane_list);
> wl_list_init(&ec->layer_list);
> @@ -4600,6 +4954,10 @@ int main(int argc, char *argv[])
> struct wl_client *primary_client;
> struct wl_listener primary_client_destroyed;
> struct weston_seat *seat;
> +#ifdef HAVE_LCMS
> + cmsUInt8Number srgb_id[17];
> + cmsUInt8Number blending_id[17];
> +#endif
>
> const struct weston_option core_options[] = {
> { WESTON_OPTION_STRING, "backend", 'B', &backend },
> @@ -4690,6 +5048,45 @@ int main(int argc, char *argv[])
> ec->idle_time = idle_time;
> ec->default_pointer_grab = NULL;
>
> +#ifdef HAVE_LCMS
> + ec->input_colorspaces =
> + g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
> + (GDestroyNotify) weston_colorspace_free);
> + ec->output_colorspaces =
> + g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
> + (GDestroyNotify) weston_colorspace_free);
> +
> + ec->srgb_colorspace.destroyable = 0;
> + ec->srgb_colorspace.input = 1;
> + ec->srgb_colorspace.compositor = ec;
> + ec->blending_colorspace.destroyable = 0;
> + ec->blending_colorspace.input = 1;
> + ec->blending_colorspace.compositor = ec;
> +
> + ec->srgb_colorspace.lcms_handle = cmsCreate_sRGBProfile();
> + /* TODO: We should really use a linear blending space. But this would
> + * cause additional banding since we only use an 8 bit LUT for now. */
> + ec->blending_colorspace.lcms_handle = cmsCreate_sRGBProfile();
> +
> + weston_build_clut(&ec->srgb_colorspace);
> + /* This is unnecessary but will initialize everything with 0 */
> + weston_build_clut(&ec->blending_colorspace);
> +
> + cmsMD5computeID(ec->srgb_colorspace.lcms_handle);
> + cmsMD5computeID(ec->blending_colorspace.lcms_handle);
> + cmsGetHeaderProfileID(ec->srgb_colorspace.lcms_handle, srgb_id);
> + cmsGetHeaderProfileID(ec->blending_colorspace.lcms_handle, blending_id);
> + srgb_id[16] = '\0';
> + blending_id[16] = '\0';
> +
> + g_hash_table_insert(ec->input_colorspaces,
> + g_strdup((const gchar *) srgb_id),
> + &ec->srgb_colorspace);
> + g_hash_table_insert(ec->input_colorspaces,
> + g_strdup((const gchar *) blending_id),
> + &ec->srgb_colorspace);
> +#endif
> +
> for (i = 1; i < argc; i++)
> weston_log("fatal: unhandled option: %s\n", argv[i]);
> if (argc > 1) {
> @@ -4760,6 +5157,14 @@ out:
>
> wl_signal_emit(&ec->destroy_signal, ec);
>
> +#ifdef HAVE_LCMS
> + g_hash_table_unref(ec->input_colorspaces);
> + g_hash_table_unref(ec->output_colorspaces);
> +
> + weston_free_clut(&ec->srgb_colorspace.clut);
> + /* The blending colorspace cannot have a clut */
> +#endif
> +
> weston_compositor_xkb_destroy(ec);
>
> ec->destroy(ec);
> diff --git a/src/compositor.h b/src/compositor.h
> index 44379fe..5f198a9 100644
> --- a/src/compositor.h
> +++ b/src/compositor.h
> @@ -31,6 +31,7 @@ extern "C" {
> #include <time.h>
> #include <pixman.h>
> #include <xkbcommon/xkbcommon.h>
> +#include <glib.h>
>
> #define WL_HIDE_DEPRECATED
> #include <wayland-server.h>
> @@ -40,6 +41,10 @@ extern "C" {
> #include "config-parser.h"
> #include "zalloc.h"
>
> +#ifdef HAVE_LCMS
> +#include <lcms2.h>
> +#endif
> +
> #ifndef MIN
> #define MIN(x,y) (((x) < (y)) ? (x) : (y))
> #endif
> @@ -179,6 +184,24 @@ enum weston_mode_switch_op {
> WESTON_MODE_SWITCH_RESTORE_NATIVE
> };
>
> +struct weston_clut {
> + unsigned points;
> + char *data;
> +};
> +
> +struct weston_colorspace {
> +#ifdef HAVE_LCMS
> + cmsHPROFILE lcms_handle;
> +#endif
> + struct weston_clut clut;
> +
> + int destroyable;
> + int refcount;
> + int input;
> +
> + struct weston_compositor *compositor;
> +};
> +
> struct weston_output {
> uint32_t id;
> char *name;
> @@ -220,6 +243,8 @@ struct weston_output {
> struct weston_mode *original_mode;
> struct wl_list mode_list;
>
> + struct weston_colorspace *colorspace;
> +
> void (*start_repaint_loop)(struct weston_output *output);
> int (*repaint)(struct weston_output *output,
> pixman_region32_t *damage);
> @@ -668,6 +693,11 @@ struct weston_compositor {
> int32_t kb_repeat_delay;
>
> clockid_t presentation_clock;
> +
> + struct weston_colorspace srgb_colorspace;
> + struct weston_colorspace blending_colorspace;
> + GHashTable *input_colorspaces;
> + GHashTable *output_colorspaces;
> };
>
> struct weston_buffer {
> @@ -844,6 +874,9 @@ struct weston_surface_state {
> /* wl_surface.set_scaling_factor */
> /* wl_viewport.set */
> struct weston_buffer_viewport buffer_viewport;
> +
> + /* wl_cms.set_colorspace*/
> + struct weston_colorspace *colorspace;
> };
>
> struct weston_surface {
> @@ -887,6 +920,8 @@ struct weston_surface {
> int32_t height_from_buffer;
> int keep_buffer; /* bool for backends to prevent early release */
>
> + struct weston_colorspace *colorspace;
> +
> /* wl_viewport resource for this surface */
> struct wl_resource *viewport_resource;
>
> @@ -1410,6 +1445,12 @@ struct weston_view_animation *
> weston_slide_run(struct weston_view *view, float start, float stop,
> weston_view_animation_done_func_t done, void *data);
>
> +struct weston_colorspace *
> +weston_colorspace_from_fd(int fd, int input, struct weston_compositor *ec);
> +
> +void
> +weston_colorspace_destroy(struct weston_colorspace *colorspace);
> +
> void
> weston_surface_set_color(struct weston_surface *surface,
> float red, float green, float blue, float alpha);
> --
> 2.1.2
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
More information about the wayland-devel
mailing list