libweston: add struct weston_drm_format
Add struct weston_drm_format, which contains a DRM format and a list of modifiers. The patch also adds struct weston_drm_format_array and some helper functions to handle these two new structs: init/fini, find elements, add elements, etc. This will be useful in the next commits in which we add support to dmabuf-hints. It also allows a cleanup in the DRM-backend, where we currently have a similar struct in drm_plane but with no helper functions, so the code to handle it is scattered throughout the functions and there is a lot of repetition. This patch is based on previous work of Scott Anderson (@ascent). Signed-off-by: Scott Anderson <scott.anderson@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
This commit is contained in:
parent
4b5df8b39f
commit
78f01927b6
516
libweston/drm-formats.c
Normal file
516
libweston/drm-formats.c
Normal file
@ -0,0 +1,516 @@
|
||||
/*
|
||||
* Copyright © 2021 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 <assert.h>
|
||||
|
||||
#include <libweston/libweston.h>
|
||||
#include "libweston-internal.h"
|
||||
#include "shared/weston-drm-fourcc.h"
|
||||
|
||||
/**
|
||||
* Create and initialize a weston_drm_format_array
|
||||
*
|
||||
* @return The weston_drm_format_array, or NULL on failure
|
||||
*/
|
||||
WL_EXPORT struct weston_drm_format_array *
|
||||
weston_drm_format_array_create(void)
|
||||
{
|
||||
struct weston_drm_format_array *formats;
|
||||
|
||||
formats = zalloc(sizeof(*formats));
|
||||
if (!formats) {
|
||||
weston_log("%s: out of memory\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
weston_drm_format_array_init(formats);
|
||||
|
||||
return formats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a weston_drm_format_array
|
||||
*
|
||||
* @param formats The weston_drm_format_array to initialize
|
||||
*/
|
||||
WL_EXPORT void
|
||||
weston_drm_format_array_init(struct weston_drm_format_array *formats)
|
||||
{
|
||||
wl_array_init(&formats->arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fini and destroy a weston_drm_format_array
|
||||
*
|
||||
* @param formats The weston_drm_format_array to destroy
|
||||
*/
|
||||
WL_EXPORT void
|
||||
weston_drm_format_array_destroy(struct weston_drm_format_array *formats)
|
||||
{
|
||||
weston_drm_format_array_fini(formats);
|
||||
free(formats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish a weston_drm_format_array
|
||||
*
|
||||
* It releases the modifiers set for each format and then the
|
||||
* formats array itself.
|
||||
*
|
||||
* @param formats The weston_drm_format_array to finish
|
||||
*/
|
||||
WL_EXPORT void
|
||||
weston_drm_format_array_fini(struct weston_drm_format_array *formats)
|
||||
{
|
||||
struct weston_drm_format *fmt;
|
||||
|
||||
wl_array_for_each(fmt, &formats->arr)
|
||||
wl_array_release(&fmt->modifiers);
|
||||
|
||||
wl_array_release(&formats->arr);
|
||||
}
|
||||
|
||||
static int
|
||||
add_format_and_modifiers(struct weston_drm_format_array *formats,
|
||||
uint32_t format, struct wl_array *modifiers)
|
||||
{
|
||||
struct weston_drm_format *fmt;
|
||||
int ret;
|
||||
|
||||
fmt = weston_drm_format_array_add_format(formats, format);
|
||||
if (!fmt)
|
||||
return -1;
|
||||
|
||||
ret = wl_array_copy(&fmt->modifiers, modifiers);
|
||||
if (ret < 0) {
|
||||
weston_log("%s: out of memory\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the content of a weston_drm_format_array
|
||||
*
|
||||
* Frees the content of the array and then perform a deep copy using
|
||||
* source_formats. It duplicates the array of formats and for each format it
|
||||
* duplicates the modifiers set as well.
|
||||
*
|
||||
* @param formats The weston_drm_format_array that gets its content replaced
|
||||
* @param source_formats The weston_drm_format_array to copy
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
WL_EXPORT int
|
||||
weston_drm_format_array_replace(struct weston_drm_format_array *formats,
|
||||
const struct weston_drm_format_array *source_formats)
|
||||
{
|
||||
struct weston_drm_format *source_fmt;
|
||||
int ret;
|
||||
|
||||
weston_drm_format_array_fini(formats);
|
||||
weston_drm_format_array_init(formats);
|
||||
|
||||
wl_array_for_each(source_fmt, &source_formats->arr) {
|
||||
ret = add_format_and_modifiers(formats, source_fmt->format,
|
||||
&source_fmt->modifiers);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add format to weston_drm_format_array
|
||||
*
|
||||
* Adding repeated formats is considered an error.
|
||||
*
|
||||
* @param formats The weston_drm_format_array that receives the format
|
||||
* @param format The format to add to the array
|
||||
* @return The weston_drm_format, or NULL on failure
|
||||
*/
|
||||
WL_EXPORT struct weston_drm_format *
|
||||
weston_drm_format_array_add_format(struct weston_drm_format_array *formats,
|
||||
uint32_t format)
|
||||
{
|
||||
struct weston_drm_format *fmt;
|
||||
|
||||
/* We should not try to add repeated formats to an array. */
|
||||
assert(!weston_drm_format_array_find_format(formats, format));
|
||||
|
||||
fmt = wl_array_add(&formats->arr, sizeof(*fmt));
|
||||
if (!fmt) {
|
||||
weston_log("%s: out of memory\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fmt->format = format;
|
||||
wl_array_init(&fmt->modifiers);
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove latest format added to a weston_drm_format_array
|
||||
*
|
||||
* Calling this function for an empty array is an error, at least one element
|
||||
* must be in the array.
|
||||
*
|
||||
* @param formats The weston_drm_format_array from which the format is removed
|
||||
*/
|
||||
WL_EXPORT void
|
||||
weston_drm_format_array_remove_latest_format(struct weston_drm_format_array *formats)
|
||||
{
|
||||
struct wl_array *array = &formats->arr;
|
||||
struct weston_drm_format *fmt;
|
||||
|
||||
assert(array->size >= sizeof(*fmt));
|
||||
|
||||
array->size -= sizeof(*fmt);
|
||||
|
||||
fmt = array->data + array->size;
|
||||
wl_array_release(&fmt->modifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find format in a weston_drm_format_array
|
||||
*
|
||||
* @param formats The weston_drm_format_array where to look for the format
|
||||
* @param format The format to look for
|
||||
* @return The weston_drm_format if format was found, or NULL otherwise
|
||||
*/
|
||||
WL_EXPORT struct weston_drm_format *
|
||||
weston_drm_format_array_find_format(const struct weston_drm_format_array *formats,
|
||||
uint32_t format)
|
||||
{
|
||||
struct weston_drm_format *fmt;
|
||||
|
||||
wl_array_for_each(fmt, &formats->arr)
|
||||
if (fmt->format == format)
|
||||
return fmt;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the content of two weston_drm_format_array
|
||||
*
|
||||
* @param formats_A One of the weston_drm_format_array to compare
|
||||
* @param formats_B The other weston_drm_format_array to compare
|
||||
* @return True if both sets are equivalent, false otherwise
|
||||
*/
|
||||
WL_EXPORT bool
|
||||
weston_drm_format_array_equal(const struct weston_drm_format_array *formats_A,
|
||||
const struct weston_drm_format_array *formats_B)
|
||||
{
|
||||
struct weston_drm_format *fmt_A, *fmt_B;
|
||||
const uint64_t *modifiers_A;
|
||||
unsigned num_modifiers_A, num_modifiers_B;
|
||||
unsigned int i;
|
||||
|
||||
if (formats_A->arr.size != formats_B->arr.size)
|
||||
return false;
|
||||
|
||||
wl_array_for_each(fmt_A, &formats_A->arr) {
|
||||
fmt_B = weston_drm_format_array_find_format(formats_B,
|
||||
fmt_A->format);
|
||||
if (!fmt_B)
|
||||
return false;
|
||||
|
||||
modifiers_A = weston_drm_format_get_modifiers(fmt_A, &num_modifiers_A);
|
||||
weston_drm_format_get_modifiers(fmt_B, &num_modifiers_B);
|
||||
if (num_modifiers_A != num_modifiers_B)
|
||||
return false;
|
||||
for (i = 0; i < num_modifiers_A; i++)
|
||||
if (!weston_drm_format_has_modifier(fmt_B, modifiers_A[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins two weston_drm_format_array, keeping the result in A
|
||||
*
|
||||
* @param formats_A The weston_drm_format_array that receives the formats from B
|
||||
* @param formats_B The weston_drm_format_array whose formats are added to A
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
WL_EXPORT int
|
||||
weston_drm_format_array_join(struct weston_drm_format_array *formats_A,
|
||||
const struct weston_drm_format_array *formats_B)
|
||||
{
|
||||
struct weston_drm_format *fmt_A, *fmt_B;
|
||||
const uint64_t *modifiers;
|
||||
unsigned int num_modifiers;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
wl_array_for_each(fmt_B, &formats_B->arr) {
|
||||
fmt_A = weston_drm_format_array_find_format(formats_A,
|
||||
fmt_B->format);
|
||||
if (!fmt_A) {
|
||||
fmt_A = weston_drm_format_array_add_format(formats_A,
|
||||
fmt_B->format);
|
||||
if (!fmt_A)
|
||||
return -1;
|
||||
}
|
||||
|
||||
modifiers = weston_drm_format_get_modifiers(fmt_B, &num_modifiers);
|
||||
for (i = 0; i < num_modifiers; i++) {
|
||||
if (weston_drm_format_has_modifier(fmt_A, modifiers[i]))
|
||||
continue;
|
||||
ret = weston_drm_format_add_modifier(fmt_A, modifiers[i]);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
modifiers_intersect(const struct weston_drm_format *fmt_A,
|
||||
const struct weston_drm_format *fmt_B,
|
||||
struct wl_array *modifiers_result)
|
||||
{
|
||||
const uint64_t *modifiers;
|
||||
unsigned int num_modifiers;
|
||||
uint64_t *mod;
|
||||
unsigned int i;
|
||||
|
||||
modifiers = weston_drm_format_get_modifiers(fmt_A, &num_modifiers);
|
||||
for (i = 0; i < num_modifiers; i++) {
|
||||
if (!weston_drm_format_has_modifier(fmt_B, modifiers[i]))
|
||||
continue;
|
||||
mod = wl_array_add(modifiers_result, sizeof(modifiers[i]));
|
||||
if (!mod) {
|
||||
weston_log("%s: out of memory\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
*mod = modifiers[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the intersection between two DRM-format arrays
|
||||
*
|
||||
* Callers are responsible for destroying the returned array.
|
||||
*
|
||||
* @param formats_A One of the weston_drm_format_array
|
||||
* @param formats_B The other weston_drm_format_array
|
||||
* @return Array with formats and modifiers that are present
|
||||
* on both A and B, or NULL on failure
|
||||
*/
|
||||
WL_EXPORT struct weston_drm_format_array *
|
||||
weston_drm_format_array_intersect(const struct weston_drm_format_array *formats_A,
|
||||
const struct weston_drm_format_array *formats_B)
|
||||
{
|
||||
struct weston_drm_format_array *formats_result;
|
||||
struct weston_drm_format *fmt_result, *fmt_A, *fmt_B;
|
||||
int ret;
|
||||
|
||||
formats_result = weston_drm_format_array_create();
|
||||
if (!formats_result)
|
||||
return NULL;
|
||||
|
||||
wl_array_for_each(fmt_A, &formats_A->arr) {
|
||||
fmt_B = weston_drm_format_array_find_format(formats_B,
|
||||
fmt_A->format);
|
||||
if (!fmt_B)
|
||||
continue;
|
||||
|
||||
fmt_result = weston_drm_format_array_add_format(formats_result,
|
||||
fmt_A->format);
|
||||
if (!fmt_result)
|
||||
goto err;
|
||||
|
||||
ret = modifiers_intersect(fmt_A, fmt_B, &fmt_result->modifiers);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
if (fmt_result->modifiers.size == 0)
|
||||
weston_drm_format_array_remove_latest_format(formats_result);
|
||||
}
|
||||
|
||||
return formats_result;
|
||||
|
||||
err:
|
||||
weston_drm_format_array_destroy(formats_result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
modifiers_subtract(const struct weston_drm_format *fmt_A,
|
||||
const struct weston_drm_format *fmt_B,
|
||||
struct wl_array *modifiers_result)
|
||||
{
|
||||
const uint64_t *modifiers;
|
||||
unsigned int num_modifiers;
|
||||
uint64_t *mod;
|
||||
unsigned int i;
|
||||
|
||||
modifiers = weston_drm_format_get_modifiers(fmt_A, &num_modifiers);
|
||||
for (i = 0; i < num_modifiers; i++) {
|
||||
if (weston_drm_format_has_modifier(fmt_B, modifiers[i]))
|
||||
continue;
|
||||
mod = wl_array_add(modifiers_result, sizeof(modifiers[i]));
|
||||
if (!mod) {
|
||||
weston_log("%s: out of memory\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
*mod = modifiers[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the subtraction between two DRM-format arrays, keeping the result in A
|
||||
*
|
||||
* @param formats_A The minuend weston_drm_format_array
|
||||
* @param formats_B The subtrahend weston_drm_format_array
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
WL_EXPORT int
|
||||
weston_drm_format_array_subtract(struct weston_drm_format_array *formats_A,
|
||||
const struct weston_drm_format_array *formats_B)
|
||||
{
|
||||
struct weston_drm_format_array *formats_result;
|
||||
struct weston_drm_format *fmt_result, *fmt_A, *fmt_B;
|
||||
int ret;
|
||||
|
||||
formats_result = weston_drm_format_array_create();
|
||||
if (!formats_result)
|
||||
return -1;
|
||||
|
||||
wl_array_for_each(fmt_A, &formats_A->arr) {
|
||||
fmt_B = weston_drm_format_array_find_format(formats_B,
|
||||
fmt_A->format);
|
||||
if (!fmt_B) {
|
||||
ret = add_format_and_modifiers(formats_result, fmt_A->format,
|
||||
&fmt_A->modifiers);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
fmt_result = weston_drm_format_array_add_format(formats_result,
|
||||
fmt_A->format);
|
||||
if (!fmt_result)
|
||||
goto err;
|
||||
|
||||
ret = modifiers_subtract(fmt_A, fmt_B, &fmt_result->modifiers);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
if (fmt_result->modifiers.size == 0)
|
||||
weston_drm_format_array_remove_latest_format(formats_result);
|
||||
}
|
||||
|
||||
ret = weston_drm_format_array_replace(formats_A, formats_result);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
weston_drm_format_array_destroy(formats_result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add modifier to modifier set of a weston_drm_format.
|
||||
*
|
||||
* Adding repeated modifiers is considered an error.
|
||||
*
|
||||
* @param format The weston_drm_format that owns the modifier set to which
|
||||
* the modifier should be added
|
||||
* @param modifier The modifier to add
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
WL_EXPORT int
|
||||
weston_drm_format_add_modifier(struct weston_drm_format *format,
|
||||
uint64_t modifier)
|
||||
{
|
||||
uint64_t *mod;
|
||||
|
||||
/* We should not try to add repeated modifiers to a set. */
|
||||
assert(!weston_drm_format_has_modifier(format, modifier));
|
||||
|
||||
mod = wl_array_add(&format->modifiers, sizeof(*mod));
|
||||
if (!mod) {
|
||||
weston_log("%s: out of memory\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
*mod = modifier;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if modifier set of a weston_drm_format contains a certain modifier
|
||||
*
|
||||
* @param format The weston_drm_format that owns the modifier set where to
|
||||
* look for the modifier
|
||||
* @param modifier The modifier to look for
|
||||
* @return True if modifier was found, false otherwise
|
||||
*/
|
||||
WL_EXPORT bool
|
||||
weston_drm_format_has_modifier(const struct weston_drm_format *format,
|
||||
uint64_t modifier)
|
||||
{
|
||||
const uint64_t *modifiers;
|
||||
unsigned int num_modifiers;
|
||||
unsigned int i;
|
||||
|
||||
modifiers = weston_drm_format_get_modifiers(format, &num_modifiers);
|
||||
for (i = 0; i < num_modifiers; i++)
|
||||
if (modifiers[i] == modifier)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array of modifiers and modifiers count from a weston_drm_format
|
||||
*
|
||||
* @param format The weston_drm_format that contains the modifiers
|
||||
* @param count_out Parameter that receives the modifiers count
|
||||
* @return The array of modifiers
|
||||
*/
|
||||
WL_EXPORT const uint64_t *
|
||||
weston_drm_format_get_modifiers(const struct weston_drm_format *format,
|
||||
unsigned int *count_out)
|
||||
{
|
||||
*count_out = format->modifiers.size / sizeof(uint64_t);
|
||||
return format->modifiers.data;
|
||||
}
|
@ -325,6 +325,72 @@ void
|
||||
weston_protected_surface_send_event(struct protected_surface *psurface,
|
||||
enum weston_hdcp_protection protection);
|
||||
|
||||
/* weston_drm_format */
|
||||
|
||||
struct weston_drm_format {
|
||||
uint32_t format;
|
||||
struct wl_array modifiers;
|
||||
};
|
||||
|
||||
struct weston_drm_format_array {
|
||||
struct wl_array arr;
|
||||
};
|
||||
|
||||
struct weston_drm_format_array *
|
||||
weston_drm_format_array_create(void);
|
||||
|
||||
void
|
||||
weston_drm_format_array_init(struct weston_drm_format_array *formats);
|
||||
|
||||
void
|
||||
weston_drm_format_array_destroy(struct weston_drm_format_array *formats);
|
||||
|
||||
void
|
||||
weston_drm_format_array_fini(struct weston_drm_format_array *formats);
|
||||
|
||||
int
|
||||
weston_drm_format_array_replace(struct weston_drm_format_array *formats,
|
||||
const struct weston_drm_format_array *source_formats);
|
||||
|
||||
struct weston_drm_format *
|
||||
weston_drm_format_array_add_format(struct weston_drm_format_array *formats,
|
||||
uint32_t format);
|
||||
|
||||
void
|
||||
weston_drm_format_array_remove_latest_format(struct weston_drm_format_array *formats);
|
||||
|
||||
struct weston_drm_format *
|
||||
weston_drm_format_array_find_format(const struct weston_drm_format_array *formats,
|
||||
uint32_t format);
|
||||
|
||||
bool
|
||||
weston_drm_format_array_equal(const struct weston_drm_format_array *formats_A,
|
||||
const struct weston_drm_format_array *formats_B);
|
||||
|
||||
int
|
||||
weston_drm_format_array_join(struct weston_drm_format_array *formats_A,
|
||||
const struct weston_drm_format_array *formats_B);
|
||||
|
||||
struct weston_drm_format_array *
|
||||
weston_drm_format_array_intersect(const struct weston_drm_format_array *formats_A,
|
||||
const struct weston_drm_format_array *formats_B);
|
||||
|
||||
int
|
||||
weston_drm_format_array_subtract(struct weston_drm_format_array *formats_A,
|
||||
const struct weston_drm_format_array *formats_B);
|
||||
|
||||
int
|
||||
weston_drm_format_add_modifier(struct weston_drm_format *format,
|
||||
uint64_t modifier);
|
||||
|
||||
bool
|
||||
weston_drm_format_has_modifier(const struct weston_drm_format *format,
|
||||
uint64_t modifier);
|
||||
|
||||
const uint64_t *
|
||||
weston_drm_format_get_modifiers(const struct weston_drm_format *format,
|
||||
unsigned int *count_out);
|
||||
|
||||
/* others */
|
||||
int
|
||||
wl_data_device_manager_init(struct wl_display *display);
|
||||
|
@ -15,6 +15,7 @@ srcs_libweston = [
|
||||
'compositor.c',
|
||||
'content-protection.c',
|
||||
'data-device.c',
|
||||
'drm-formats.c',
|
||||
'input.c',
|
||||
'linux-dmabuf.c',
|
||||
'linux-explicit-synchronization.c',
|
||||
|
Loading…
Reference in New Issue
Block a user