libweston: add unique id generator

This is preparation for the CM&HDR protocol implementation. It requires
us to give a unique id to each color-profile, so let's do that.

In this commit we introduce a generic id generator to libweston, and
its first user: the color-profile.

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
This commit is contained in:
Leandro Ribeiro 2024-01-10 18:49:17 -03:00
parent ba1561946f
commit a84806a88e
9 changed files with 281 additions and 0 deletions

View file

@ -1438,6 +1438,8 @@ struct weston_compositor {
uint32_t capabilities; /* combination of enum weston_capability */
struct weston_color_manager *color_manager;
struct weston_idalloc *color_profile_id_generator;
struct weston_renderer *renderer;
const struct pixel_format_info *read_format;

View file

@ -37,6 +37,7 @@
#include <string.h>
#include "color.h"
#include "id-number-allocator.h"
#include "libweston-internal.h"
#include <libweston/weston-log.h>
#include "shared/xalloc.h"
@ -73,6 +74,9 @@ weston_color_profile_unref(struct weston_color_profile *cprof)
if (--cprof->ref_count > 0)
return;
weston_idalloc_put_id(cprof->cm->compositor->color_profile_id_generator,
cprof->id);
cprof->cm->destroy_color_profile(cprof);
}
@ -109,6 +113,7 @@ weston_color_profile_init(struct weston_color_profile *cprof,
{
cprof->cm = cm;
cprof->ref_count = 1;
cprof->id = weston_idalloc_get_id(cm->compositor->color_profile_id_generator);
}
/**

View file

@ -40,6 +40,9 @@ struct weston_color_profile {
struct weston_color_manager *cm;
int ref_count;
char *description;
/* Unique id to be used by the CM&HDR protocol extension. */
uint32_t id;
};
/** Type or formula for a curve */

View file

@ -80,6 +80,7 @@
#include "backend.h"
#include "libweston-internal.h"
#include "color.h"
#include "id-number-allocator.h"
#include "output-capture.h"
#include "pixman-renderer.h"
#include "renderer-gl/gl-renderer.h"
@ -9171,6 +9172,11 @@ weston_compositor_shutdown(struct weston_compositor *ec)
ec->color_manager = NULL;
}
/* Already destroyed color manager, now we can safely destroy the color
* profile id generator. */
weston_idalloc_destroy(ec->color_profile_id_generator);
ec->color_profile_id_generator = NULL;
if (ec->renderer)
ec->renderer->destroy(ec);
@ -9284,6 +9290,9 @@ weston_compositor_backends_loaded(struct weston_compositor *compositor)
if (!compositor->color_manager)
return -1;
/* Create id generator before initing the color manager. */
compositor->color_profile_id_generator = weston_idalloc_create(compositor);
if (!compositor->color_manager->init(compositor->color_manager))
return -1;

View file

@ -0,0 +1,185 @@
/*
* Copyright 2024 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include "id-number-allocator.h"
#include "shared/helpers.h"
#include "shared/xalloc.h"
#include "shared/weston-assert.h"
struct weston_idalloc {
struct weston_compositor *compositor;
/* Each value on this array is a bucket of size 32. Bit is 0 if the id
* is available, 1 otherwise. */
uint32_t *buckets;
uint32_t num_buckets;
uint32_t lowest_free_bucket;
};
/**
* Creates a unique id allocator
*
* \param compositor The compositor
* \return The unique id allocator
*/
WESTON_EXPORT_FOR_TESTS struct weston_idalloc *
weston_idalloc_create(struct weston_compositor *compositor)
{
struct weston_idalloc *idalloc;
idalloc = xzalloc(sizeof(*idalloc));
idalloc->compositor = compositor;
/* Start with 2 buckets. If necessary we increase that on demand. */
idalloc->num_buckets = 2;
idalloc->buckets = xzalloc(idalloc->num_buckets * sizeof(*idalloc->buckets));
/* Let's reserve id 0 for errors. So start with id 0 already taken. Set
* the first bit of the first bucket to 1. */
idalloc->buckets[idalloc->lowest_free_bucket] = 1;
return idalloc;
}
/**
* Destroys a unique id allocator
*
* \param idalloc The unique id allocator to destroy
*/
WESTON_EXPORT_FOR_TESTS void
weston_idalloc_destroy(struct weston_idalloc *idalloc)
{
/* Sanity check: id 0 should still be taken. */
weston_assert_true(idalloc->compositor, idalloc->buckets[0] & 1);
free(idalloc->buckets);
free(idalloc);
}
static void
update_lowest_free_bucket(struct weston_idalloc *idalloc)
{
uint32_t old_lowest_free_bucket = idalloc->lowest_free_bucket;
uint32_t *bucket;
unsigned int i;
for (i = old_lowest_free_bucket; i < idalloc->num_buckets; i++) {
bucket = &idalloc->buckets[i];
/* Skip full bucket */
if (*bucket == 0xffffffff)
continue;
idalloc->lowest_free_bucket = i;
return;
}
/* We didn't find any free bucket, so we need to add more buckets. The
* first one (from the new added) will be the lowest free. */
idalloc->lowest_free_bucket = idalloc->num_buckets;
idalloc->num_buckets *= 2;
idalloc->buckets = xrealloc(idalloc->buckets,
idalloc->num_buckets * sizeof(*idalloc->buckets));
}
/**
* Gets an id from unique id allocator
*
* \param idalloc The unique id allocator
* \return The unique id
*/
WESTON_EXPORT_FOR_TESTS uint32_t
weston_idalloc_get_id(struct weston_idalloc *idalloc)
{
uint32_t *bucket = &idalloc->buckets[idalloc->lowest_free_bucket];
unsigned int i;
uint32_t id;
/* Sanity check: lowest free bucket should not be full. */
weston_assert_uint32_neq(idalloc->compositor, *bucket, 0xffffffff);
for (i = 0; i < 32; i++) {
/* Id already used, skip it. */
if ((*bucket >> i) & 1)
continue;
/* Found free id, take it and set it to 1 on the bucket. */
*bucket |= 1 << i;
id = (32 * idalloc->lowest_free_bucket) + i;
/* Bucket may become full... */
if (*bucket == 0xffffffff)
update_lowest_free_bucket(idalloc);
return id;
}
/* We need to find an available id. */
weston_assert_not_reached(idalloc->compositor,
"should be able to allocate unique id");
}
/**
* Releases a id back to unique id allocator
*
* When an id from the unique id allocator will not be used anymore, users
* should call this function so that this id can be advertised again by the id
* allocator.
*
* \param idalloc The unique id allocator
* \param id The id to release
*/
WESTON_EXPORT_FOR_TESTS void
weston_idalloc_put_id(struct weston_idalloc *idalloc, uint32_t id)
{
uint32_t bucket_index = id / 32;
uint32_t id_index_on_bucket = id % 32;
uint32_t *bucket;
/* Shouldn't try to release index 0, we never advertise this id to anyone. */
weston_assert_uint32_neq(idalloc->compositor, id, 0);
/* Bucket index should be lower than num_buckets. */
weston_assert_uint32_lt(idalloc->compositor,
bucket_index, idalloc->num_buckets);
bucket = &idalloc->buckets[bucket_index];
/* Shouldn't try to release a free index. */
weston_assert_true(idalloc->compositor,
(*bucket >> id_index_on_bucket) & 1);
/* We now have an available index id on this bucket, so it may become
* the lowest bucket. */
if (bucket_index < idalloc->lowest_free_bucket)
idalloc->lowest_free_bucket = bucket_index;
/* Zero the bit on the bucket. */
*bucket &= ~(1 << id_index_on_bucket);
}

View file

@ -0,0 +1,45 @@
/*
* Copyright 2023 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WESTON_ID_NUMBER_ALLOCATOR_H
#define WESTON_ID_NUMBER_ALLOCATOR_H
#include <stdint.h>
struct weston_compositor;
struct weston_idalloc *
weston_idalloc_create(struct weston_compositor *compositor);
void
weston_idalloc_destroy(struct weston_idalloc *idalloc);
uint32_t
weston_idalloc_get_id(struct weston_idalloc *idalloc);
void
weston_idalloc_put_id(struct weston_idalloc *idalloc, uint32_t id);
#endif /* WESTON_ID_NUMBER_ALLOCATOR_H */

View file

@ -19,6 +19,7 @@ srcs_libweston = [
'content-protection.c',
'data-device.c',
'drm-formats.c',
'id-number-allocator.c',
'input.c',
'linux-dmabuf.c',
'linux-explicit-synchronization.c',

View file

@ -74,6 +74,13 @@ weston_assert_fail_(const struct weston_compositor *compositor, const char *fmt,
cond; \
})
#define weston_assert_not_reached(compositor, reason) \
do { \
struct weston_compositor *ec = compositor; \
custom_assert_fail_(ec, "%s:%u: Assertion failed! This should not be reached: %s\n", \
__FILE__, __LINE__, reason); \
} while (0)
#define weston_assert_true(compositor, a) \
weston_assert_(compositor, a, true, bool, "%d", ==)
@ -89,5 +96,11 @@ weston_assert_fail_(const struct weston_compositor *compositor, const char *fmt,
#define weston_assert_double_eq(compositor, a, b) \
weston_assert_(compositor, a, b, double, "%.10g", ==)
#define weston_assert_uint32_neq(compositor, a, b) \
weston_assert_(compositor, a, b, uint32_t, "%u", !=)
#define weston_assert_uint32_lt(compositor, a, b) \
weston_assert_(compositor, a, b, uint32_t, "%u", <)
#define weston_assert_str_eq(compositor, a, b) \
weston_assert_fn_(compositor, strcmp, a, b, const char *, "%s", ==)

View file

@ -36,6 +36,7 @@
#include "libweston-internal.h"
#include "backend.h"
#include "color.h"
#include "id-number-allocator.h"
#include "shared/xalloc.h"
struct config_testcase {
@ -178,6 +179,7 @@ mock_cm_get_stock_sRGB_color_profile(struct weston_color_manager *mock_cm)
mock_cprof->cm = mock_cm;
mock_cprof->ref_count = 1;
mock_cprof->description = xstrdup("mock cprof");
mock_cprof->id = weston_idalloc_get_id(mock_cm->compositor->color_profile_id_generator);
return mock_cprof;
}
@ -209,9 +211,12 @@ TEST_P(color_characteristics_config_error, config_cases)
};
struct weston_compositor mock_compositor = {
.color_manager = &mock_cm.base,
.color_profile_id_generator = weston_idalloc_create(&mock_compositor),
};
struct weston_output mock_output = {};
mock_cm.base.compositor = &mock_compositor;
wl_list_init(&mock_compositor.plane_list);
weston_output_init(&mock_output, &mock_compositor, "mockoutput");
@ -235,6 +240,7 @@ TEST_P(color_characteristics_config_error, config_cases)
weston_config_destroy(wc);
free(logbuf);
weston_output_release(&mock_output);
weston_idalloc_destroy(mock_compositor.color_profile_id_generator);
}
/* Setting NULL resets group_mask */
@ -247,9 +253,12 @@ TEST(weston_output_set_color_characteristics_null)
};
struct weston_compositor mock_compositor = {
.color_manager = &mock_cm.base,
.color_profile_id_generator = weston_idalloc_create(&mock_compositor),
};
struct weston_output mock_output = {};
mock_cm.base.compositor = &mock_compositor;
wl_list_init(&mock_compositor.plane_list);
weston_output_init(&mock_output, &mock_compositor, "mockoutput");
@ -258,6 +267,7 @@ TEST(weston_output_set_color_characteristics_null)
assert(mock_output.color_characteristics.group_mask == 0);
weston_output_release(&mock_output);
weston_idalloc_destroy(mock_compositor.color_profile_id_generator);
}
struct value_testcase {
@ -325,12 +335,15 @@ TEST_P(hdr_metadata_type1_errors, value_cases)
};
struct weston_compositor mock_compositor = {
.color_manager = &mock_cm.base,
.color_profile_id_generator = weston_idalloc_create(&mock_compositor),
};
struct weston_output mock_output = {};
bool ret;
weston_log_set_handler(no_logger, no_logger);
mock_cm.base.compositor = &mock_compositor;
wl_list_init(&mock_compositor.plane_list);
weston_output_init(&mock_output, &mock_compositor, "mockoutput");
@ -341,6 +354,7 @@ TEST_P(hdr_metadata_type1_errors, value_cases)
weston_output_color_outcome_destroy(&mock_output.color_outcome);
weston_output_release(&mock_output);
weston_idalloc_destroy(mock_compositor.color_profile_id_generator);
}
/* Unflagged members are ignored in validity check */
@ -366,10 +380,13 @@ TEST(hdr_metadata_type1_ignore_unflagged)
};
struct weston_compositor mock_compositor = {
.color_manager = &mock_cm.base,
.color_profile_id_generator = weston_idalloc_create(&mock_compositor),
};
struct weston_output mock_output = {};
bool ret;
mock_cm.base.compositor = &mock_compositor;
wl_list_init(&mock_compositor.plane_list);
weston_log_set_handler(no_logger, no_logger);
@ -380,4 +397,5 @@ TEST(hdr_metadata_type1_ignore_unflagged)
weston_output_color_outcome_destroy(&mock_output.color_outcome);
weston_output_release(&mock_output);
weston_idalloc_destroy(mock_compositor.color_profile_id_generator);
}